summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java61
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/ConnectionManager.java2
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java55
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java70
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java161
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java11
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java203
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java31
-rw-r--r--app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java87
-rw-r--r--app/src/insecure/AndroidManifest.xml (renamed from app/src/debug/AndroidManifest.xml)0
-rw-r--r--app/src/insecure/assets/urls/cdev.bitmask.net.url (renamed from app/src/debug/assets/urls/cdev.bitmask.net.url)0
-rw-r--r--app/src/insecure/assets/urls/dev.bitmask.net.url (renamed from app/src/debug/assets/urls/dev.bitmask.net.url)4
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/ConfigurationWizard.java (renamed from app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java)43
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java (renamed from app/src/debug/java/se/leap/bitmaskclient/NewProviderDialog.java)0
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java (renamed from app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java)91
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailFragment.java (renamed from app/src/debug/java/se/leap/bitmaskclient/ProviderDetailFragment.java)222
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java (renamed from app/src/debug/java/se/leap/bitmaskclient/ProviderListContent.java)164
-rw-r--r--app/src/insecure/res/layout-xlarge/new_provider_dialog.xml (renamed from app/src/debug/res/layout-xlarge/new_provider_dialog.xml)0
-rw-r--r--app/src/insecure/res/layout/new_provider_dialog.xml (renamed from app/src/debug/res/layout/new_provider_dialog.xml)0
-rw-r--r--app/src/insecure/res/values/strings.xml (renamed from app/src/debug/res/values/strings.xml)0
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/de/blinkt/openvpn/LaunchVPN.java31
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java12
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java1
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java39
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java1
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java99
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java318
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java5
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java597
-rw-r--r--app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java2
-rw-r--r--app/src/main/java/org/spongycastle/util/encoders/Base64.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/encoders/Encoder.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemObject.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java5
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemReader.java7
-rw-r--r--app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java219
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java37
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java28
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java47
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java45
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderManager.java78
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java87
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/VpnFragment.java (renamed from app/src/main/java/se/leap/bitmaskclient/EipFragment.java)168
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java42
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java29
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java4
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java28
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java (renamed from app/src/main/java/se/leap/bitmaskclient/SessionDialog.java)31
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/userstatus/User.java (renamed from app/src/main/java/se/leap/bitmaskclient/User.java)12
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java127
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java181
-rw-r--r--app/src/main/res/drawable-hdpi/ic_account_circle.pngbin0 -> 1634 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_account_circle.pngbin0 -> 951 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_account_circle.pngbin0 -> 2114 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_account_circle.pngbin0 -> 3382 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/ic_account_circle.pngbin0 -> 4838 bytes
-rw-r--r--app/src/main/res/layout-xlarge/dashboard.xml97
-rw-r--r--app/src/main/res/layout-xlarge/eip_service_fragment.xml69
-rw-r--r--app/src/main/res/layout-xlarge/user_session_fragment.xml55
-rw-r--r--app/src/main/res/layout/dashboard.xml65
-rw-r--r--app/src/main/res/layout/eip_service_fragment.xml67
-rw-r--r--app/src/main/res/layout/user_session_fragment.xml46
-rw-r--r--app/src/main/res/menu/client_dashboard.xml10
-rwxr-xr-xapp/src/main/res/values-ca/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-cs/strings-icsopenvpn.xml26
-rwxr-xr-xapp/src/main/res/values-de/strings-icsopenvpn.xml42
-rwxr-xr-xapp/src/main/res/values-es/strings-icsopenvpn.xml43
-rw-r--r--app/src/main/res/values-es/strings.xml87
-rwxr-xr-xapp/src/main/res/values-et/strings-icsopenvpn.xml29
-rwxr-xr-xapp/src/main/res/values-fr/strings-icsopenvpn.xml34
-rwxr-xr-xapp/src/main/res/values-hu/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-in/strings-icsopenvpn.xml6
-rwxr-xr-xapp/src/main/res/values-it/strings-icsopenvpn.xml16
-rwxr-xr-xapp/src/main/res/values-ja/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-ko/strings-icsopenvpn.xml6
-rwxr-xr-xapp/src/main/res/values-nl/strings-icsopenvpn.xml16
-rw-r--r--app/src/main/res/values-nl/strings.xml2
-rwxr-xr-xapp/src/main/res/values-no/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-pl/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-pt/strings-icsopenvpn.xml18
-rwxr-xr-xapp/src/main/res/values-ro/strings-icsopenvpn.xml6
-rwxr-xr-xapp/src/main/res/values-ru/strings-icsopenvpn.xml5
-rwxr-xr-xapp/src/main/res/values-sv/strings-icsopenvpn.xml4
-rwxr-xr-xapp/src/main/res/values-tr/strings-icsopenvpn.xml18
-rwxr-xr-xapp/src/main/res/values-uk/strings-icsopenvpn.xml100
-rw-r--r--app/src/main/res/values-v21/refs.xml12
-rwxr-xr-xapp/src/main/res/values-vi/strings-icsopenvpn.xml377
-rwxr-xr-xapp/src/main/res/values-zh-rCN/strings-icsopenvpn.xml65
-rwxr-xr-xapp/src/main/res/values-zh-rTW/strings-icsopenvpn.xml4
-rw-r--r--app/src/main/res/values/refs.xml12
-rwxr-xr-xapp/src/main/res/values/strings-icsopenvpn.xml37
-rw-r--r--app/src/main/res/values/strings.xml20
-rw-r--r--app/src/main/res/values/untranslatable.xml120
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ConfigurationWizard.java (renamed from app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java)35
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java (renamed from app/src/release/java/se/leap/bitmaskclient/NewProviderDialog.java)0
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ProviderAPI.java (renamed from app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java)65
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ProviderDetailFragment.java (renamed from app/src/release/java/se/leap/bitmaskclient/ProviderDetailFragment.java)222
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java (renamed from app/src/release/java/se/leap/bitmaskclient/ProviderListContent.java)162
-rw-r--r--app/src/production/res/layout-xlarge/new_provider_dialog.xml (renamed from app/src/release/res/layout-xlarge/new_provider_dialog.xml)0
-rw-r--r--app/src/production/res/layout/new_provider_dialog.xml (renamed from app/src/release/res/layout/new_provider_dialog.xml)0
108 files changed, 3546 insertions, 2004 deletions
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java
new file mode 100644
index 00000000..9a9131fd
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/BaseTestDashboard.java
@@ -0,0 +1,61 @@
+package se.leap.bitmaskclient.test;
+
+import android.content.*;
+import android.graphics.*;
+import android.test.*;
+import android.view.*;
+
+import com.robotium.solo.*;
+
+import se.leap.bitmaskclient.*;
+
+public abstract class BaseTestDashboard extends ActivityInstrumentationTestCase2<Dashboard> {
+
+ Solo solo;
+ Context context;
+ UserStatusTestController user_status_controller;
+ VpnTestController vpn_controller;
+
+ public BaseTestDashboard() { super(Dashboard.class); }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ context = getInstrumentation().getContext();
+ solo = new Solo(getInstrumentation(), getActivity());
+ user_status_controller = new UserStatusTestController(solo);
+ vpn_controller = new VpnTestController(solo);
+ ConnectionManager.setMobileDataEnabled(true, context);
+ solo.unlockScreen();
+ if (solo.searchText(solo.getString(R.string.configuration_wizard_title)))
+ new testConfigurationWizard(solo).toDashboardAnonymously("demo.bitmask.net");
+ }
+
+ void changeProviderAndLogIn(String provider) {
+ tapSwitchProvider();
+ solo.clickOnText(provider);
+ useRegistered();
+ }
+
+ void tapSwitchProvider() {
+ solo.clickOnMenuItem(solo.getString(R.string.switch_provider_menu_option));
+ solo.waitForActivity(ConfigurationWizard.class);
+ }
+
+ private void useRegistered() {
+ String text = solo.getString(R.string.signup_or_login_button);
+ clickAndWaitForDashboard(text);
+ user_status_controller.logIn("parmegvtest10", "holahola2");
+ }
+
+ private void clickAndWaitForDashboard(String click_text) {
+ solo.clickOnText(click_text);
+ assertTrue(solo.waitForActivity(Dashboard.class, 80 * 1000));
+ }
+
+ static boolean isShownWithinConfinesOfVisibleScreen(View view) {
+ Rect scrollBounds = new Rect();
+ view.getHitRect(scrollBounds);
+ return view.getLocalVisibleRect(scrollBounds);
+ }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/ConnectionManager.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/ConnectionManager.java
index a664c885..f7ab4b1e 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/ConnectionManager.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/ConnectionManager.java
@@ -16,7 +16,7 @@ public class ConnectionManager {
try {
method.invoke(conman, enabled);
} catch (InvocationTargetException | IllegalAccessException e) {
- e.printStackTrace();
+ //e.printStackTrace();
}
}
}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java
new file mode 100644
index 00000000..91d51402
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/Screenshot.java
@@ -0,0 +1,55 @@
+package se.leap.bitmaskclient.test;
+
+import com.robotium.solo.*;
+
+import java.text.*;
+import java.util.*;
+
+public class Screenshot {
+ private static String default_name = Screenshot.class.getPackage().getName();
+ private static DateFormat date_format = DateFormat.getDateTimeInstance();
+ private static int DEFAULT_MILLISECONDS_TO_SLEEP = 500;
+ private static int milliseconds_to_sleep = 0;
+ private static Solo solo;
+
+ public static void initialize(Solo solo) {
+ Screenshot.solo = solo;
+ }
+
+ public static void take(String name) {
+ solo.takeScreenshot(name.replace(" ", "_") + " " + getTimeStamp());
+ }
+
+ public static void takeWithSleep(String name) {
+ sleepBefore();
+ take(name);
+ }
+
+ public static void take() {
+ sleepBefore();
+ solo.takeScreenshot(default_name + "_" + getTimeStamp());
+ }
+
+ public static void takeWithSleep() {
+ sleepBefore();
+ take();
+ }
+
+ private static String getTimeStamp() {
+ return date_format.format(Calendar.getInstance().getTime()).replace(" ", "_").replace("/", "_").replace(":", "_");
+ }
+
+ public static void setTimeToSleep(double seconds) {
+ long milliseconds_to_sleep = Math.round(seconds * 1000);
+ Screenshot.milliseconds_to_sleep = Math.round(milliseconds_to_sleep);
+ }
+
+ private static void sleepBefore() {
+ if(milliseconds_to_sleep == 0)
+ solo.sleep(DEFAULT_MILLISECONDS_TO_SLEEP);
+ else
+ solo.sleep(milliseconds_to_sleep);
+ milliseconds_to_sleep = 0;
+ }
+}
+
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java
new file mode 100644
index 00000000..138dfa71
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/UserStatusTestController.java
@@ -0,0 +1,70 @@
+package se.leap.bitmaskclient.test;
+
+import android.view.*;
+
+import com.robotium.solo.*;
+
+import se.leap.bitmaskclient.*;
+
+public class UserStatusTestController {
+ private final Solo solo;
+
+ public UserStatusTestController(Solo solo) {
+ this.solo = solo;
+ }
+
+ void clickUserSessionButton() {
+ solo.clickOnView(getUserSessionButton());
+ }
+
+ View getUserSessionButton() throws IllegalStateException {
+ View view = solo.getView(R.id.user_status_button);
+ if(view == null)
+ throw new IllegalStateException();
+
+ return view;
+ }
+
+ void logIn(String username, String password) {
+ solo.enterText(0, username);
+ solo.enterText(1, password);
+ solo.clickOnText(solo.getString(R.string.login_button));
+ solo.waitForDialogToClose();
+ assertLoggedIn();
+ }
+
+ private void assertLoggedIn() {
+ String log_out = solo.getString(R.string.logout_button);
+ solo.waitForText(log_out);
+ }
+
+ void assertLoggedOut() {
+ String log_in = solo.getString(R.string.login_button);
+ solo.waitForText(log_in);
+ }
+
+ void logOut() {
+ assertLoggedIn();
+ clickUserSessionButton();
+
+ solo.clickOnActionBarItem(R.string.logout_button);
+ solo.waitForDialogToClose();
+ assertLoggedOut();
+ }
+
+ boolean assertErrorLogInDialogAppears() {
+ solo.waitForDialogToOpen();
+
+ String username_hint = solo.getEditText(0).getHint().toString();
+ String correct_username_hint = solo.getString(R.string.username_hint);
+ String password_hint = solo.getEditText(1).getHint().toString();
+ String correct_password_hint = solo.getString(R.string.password_hint);
+ String user_message = solo.getText(0).toString();
+ String riseup_user_message = solo.getString(R.string.login_riseup_warning);
+
+ return username_hint.equalsIgnoreCase(correct_username_hint)
+ && password_hint.equalsIgnoreCase(correct_password_hint)
+ && !user_message.equalsIgnoreCase(riseup_user_message)
+ && !user_message.isEmpty();
+ }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
new file mode 100644
index 00000000..25d81da1
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java
@@ -0,0 +1,161 @@
+package se.leap.bitmaskclient.test;
+
+import android.graphics.*;
+import android.graphics.drawable.*;
+import android.view.*;
+import android.widget.*;
+
+import com.robotium.solo.*;
+
+import junit.framework.AssertionFailedError;
+
+import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.*;
+import se.leap.bitmaskclient.R;
+
+public class VpnTestController {
+
+ private final Solo solo;
+
+ public VpnTestController(Solo solo) {
+ this.solo = solo;
+ }
+
+ protected void turnVpnOndAndOff(String provider) {
+ clickVpnButton();
+ turningEipOn();
+ clickVpnButton();
+ turningEipOff();
+ }
+
+ protected void clickVpnButton() throws IllegalStateException {
+ Button button = getVpnButton();
+ if(!isVpnButton(button))
+ throw new IllegalStateException();
+ solo.clickOnView(button);
+ }
+
+ protected Button getVpnButton() {
+ try {
+ View button_view = solo.getView(R.id.vpn_main_button);
+ if (button_view != null)
+ return (Button) button_view;
+ else
+ return new Button(solo.getCurrentActivity());
+ } catch (AssertionFailedError e) {
+ return new Button(solo.getCurrentActivity());
+ }
+ }
+
+ private boolean isVpnButton(Button button) {
+ return !button.getText().toString().isEmpty();
+ }
+
+ protected FabButton getVpnWholeIcon() {
+ View view = solo.getView(R.id.vpn_Status_Image);
+ if (view != null)
+ return (FabButton) view;
+ else
+ return null;
+ }
+
+ protected void turningEipOn() {
+ assertInProgress();
+ int max_seconds_until_connected = 120;
+
+ Condition condition = new Condition() {
+ @Override
+ public boolean isSatisfied() {
+ return iconShowsConnected();
+ }
+ };
+ solo.waitForCondition(condition, max_seconds_until_connected * 1000);
+ sleepSeconds(2);
+ }
+
+ private void assertInProgress() {
+ FabButton whole_icon = getVpnWholeIcon();
+ ProgressRingView a;
+ a = whole_icon != null ?
+ (ProgressRingView) getVpnWholeIcon().findViewById(R.id.fabbutton_ring) :
+ new ProgressRingView(solo.getCurrentActivity());
+ BaseTestDashboard.isShownWithinConfinesOfVisibleScreen(a);
+ }
+
+ private boolean iconShowsConnected() {
+ return iconEquals(iconConnectedDrawable());
+ }
+
+ protected boolean iconShowsDisconnected() {
+ return iconEquals(iconDisconnectedDrawable());
+ }
+
+ private boolean iconEquals(Drawable drawable) {
+ Bitmap inside_icon = getVpnInsideIcon();
+ if(inside_icon != null)
+ return inside_icon.equals(drawable);
+ else
+ return false;
+
+ }
+
+ private Drawable iconConnectedDrawable() {
+ return getDrawable(R.drawable.ic_stat_vpn);
+ }
+
+ private Drawable iconDisconnectedDrawable() {
+ return getDrawable(R.drawable.ic_stat_vpn_offline);
+ }
+
+ private Drawable getDrawable(int resId) {
+ return solo.getCurrentActivity().getResources().getDrawable(resId);
+ }
+
+ private Bitmap getVpnInsideIcon() {
+ FabButton whole_icon = getVpnWholeIcon();
+
+ CircleImageView a;
+ a = whole_icon != null ?
+ (CircleImageView) getVpnWholeIcon().findViewById(R.id.fabbutton_circle)
+ : new CircleImageView(solo.getCurrentActivity());
+ a.setDrawingCacheEnabled(true);
+ return a.getDrawingCache();
+ }
+
+ protected void turningEipOff() {
+ okToBrowserWarning();
+ sayOkToDisconnect();
+
+ int max_seconds_until_connected = 1;
+
+ Condition condition = new Condition() {
+ @Override
+ public boolean isSatisfied() {
+ return iconShowsDisconnected();
+ }
+ };
+ solo.waitForCondition(condition, max_seconds_until_connected * 1000);
+ sleepSeconds(2);
+ }
+
+ private void okToBrowserWarning() {
+ solo.waitForDialogToOpen();
+ clickYes();
+ }
+
+ private void clickYes() {
+ String yes = solo.getString(android.R.string.yes);
+ solo.clickOnText(yes);
+ }
+
+ private void sayOkToDisconnect() throws IllegalStateException {
+ boolean disconnect_vpn_appeared = solo.waitForActivity(DisconnectVPN.class);
+ if(disconnect_vpn_appeared)
+ clickYes();
+ else throw new IllegalStateException();
+ }
+
+ void sleepSeconds(int seconds) {
+ solo.sleep(seconds * 1000);
+ }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
index 1fa4cf2f..931457ee 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testConfigurationWizard.java
@@ -13,6 +13,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
private Solo solo;
private static int added_providers;
+ private boolean executing_from_dashboard = false;
public testConfigurationWizard() {
super(ConfigurationWizard.class);
@@ -21,18 +22,21 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
public testConfigurationWizard(Solo solo) {
super(ConfigurationWizard.class);
this.solo = solo;
+ executing_from_dashboard = true;
}
@Override
protected void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
- ConnectionManager.setMobileDataEnabled(true, solo.getCurrentActivity().getApplicationContext());
+ //ConnectionManager.setMobileDataEnabled(true, solo.getCurrentActivity().getApplicationContext());
}
@Override
protected void tearDown() throws Exception {
-
+ if(!executing_from_dashboard)
+ solo.finishOpenedActivities();
+ super.tearDown();
}
public void testListProviders() {
@@ -68,7 +72,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
private void waitForProviderDetails() {
String text = solo.getString(R.string.provider_details_fragment_title);
- assertTrue("Provider details dialog did not appear", solo.waitForText(text));
+ assertTrue("Provider details dialog did not appear", solo.waitForText(text, 1, 60*1000));
}
public void testAddNewProvider() {
@@ -77,6 +81,7 @@ public class testConfigurationWizard extends ActivityInstrumentationTestCase2<Co
private void addProvider(String url) {
boolean is_new_provider = !solo.searchText(url);
+
if (is_new_provider)
added_providers = added_providers + 1;
solo.clickOnActionBarItem(R.id.new_provider);
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
index d2fb9901..fea6bf77 100644
--- a/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testDashboardIntegration.java
@@ -1,136 +1,29 @@
package se.leap.bitmaskclient.test;
-import android.content.*;
-import android.test.*;
-import android.widget.*;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.widget.Button;
import com.robotium.solo.*;
import java.io.*;
import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.CircleImageView;
+import mbanje.kurt.fabbutton.FabButton;
+import mbanje.kurt.fabbutton.ProgressRingView;
import se.leap.bitmaskclient.*;
-public class testDashboardIntegration extends ActivityInstrumentationTestCase2<Dashboard> {
-
- private Solo solo;
- private Context context;
-
- public testDashboardIntegration() {
- super(Dashboard.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- context = getInstrumentation().getContext();
- solo = new Solo(getInstrumentation(), getActivity());
- ConnectionManager.setMobileDataEnabled(true, context);
- solo.unlockScreen();
- if (solo.searchText(solo.getString(R.string.configuration_wizard_title)))
- new testConfigurationWizard(solo).toDashboardAnonymously("demo.bitmask.net");
- }
+public class testDashboardIntegration extends BaseTestDashboard {
@Override
protected void tearDown() throws Exception {
solo.finishOpenedActivities();
}
- /**
- * This test will fail if Android does not trust VPN connection.
- * I cannot automate that dialog.
- */
- public void testOnOffOpenVpn() {
- solo.clickOnView(solo.getView(R.id.eipSwitch));
- turningEipOn();
-
- solo.clickOnView(solo.getView(R.id.eipSwitch));
- turningEipOff();
-
- solo.clickOnView(solo.getView(R.id.eipSwitch));
- turningEipOn();
-
- solo.clickOnView(solo.getView(R.id.eipSwitch));
- turningEipOff();
-
- /*solo.clickOnView(solo.getView(R.id.eipSwitch));
- turningEipOn();
-
- turnNetworkOff();
- restartAdbServer(); // This doesn't work
- */
-
- }
-
- private void turningEipOn() {
- assertAuthenticating();
- int max_seconds_until_connected = 30;
- assertConnected(max_seconds_until_connected);
- solo.sleep(2 * 1000);
- }
-
- private void assertAuthenticating() {
- String message = solo.getString(R.string.state_auth);
- assertTrue(solo.waitForText(message));
- }
-
- private void assertConnected(int max_seconds_until_connected) {
- String message = solo.getString(R.string.eip_state_connected);
- assertTrue(solo.waitForText(message, 1, max_seconds_until_connected * 1000));
- }
-
- private void turningEipOff() {
- sayOkToDisconnect();
- assertDisconnected();
- solo.sleep(2 * 1000);
- }
-
- private void sayOkToDisconnect() {
- assertTrue(solo.waitForActivity(DisconnectVPN.class));
- String yes = solo.getString(android.R.string.yes);
- solo.clickOnText(yes);
- }
-
- private void assertDisconnected() {
- String message = solo.getString(R.string.eip_state_not_connected);
- assertTrue(solo.waitForText(message));
- }
-
- private void turnNetworkOff() {
- ConnectionManager.setMobileDataEnabled(false, context);
- if (!solo.waitForText(getActivity().getString(R.string.eip_state_not_connected), 1, 15 * 1000))
- fail();
- }
-
- private void restartAdbServer() {
- runAdbCommand("kill-server");
- runAdbCommand("start-server");
- }
-
- public void testLogInAndOut() {
- long milliseconds_to_log_in = 40 * 1000;
- solo.clickOnActionBarItem(R.id.login_button);
- logIn("parmegvtest1", " S_Zw3'-");
- solo.waitForDialogToClose(milliseconds_to_log_in);
- assertSuccessfulLogin();
-
- logOut();
- }
-
- private void logIn(String username, String password) {
- solo.enterText(0, username);
- solo.enterText(1, password);
- solo.clickOnText("Log In");
- solo.waitForDialogToClose();
- }
-
- private void assertSuccessfulLogin() {
- assertTrue(solo.waitForText("is logged in"));
- }
-
- private void logOut() {
- solo.clickOnActionBarItem(R.string.logout_button);
- assertTrue(solo.waitForDialogToClose());
+ public void testSwitchProvider() {
+ tapSwitchProvider();
+ solo.goBack();
}
public void testShowAbout() {
@@ -141,79 +34,25 @@ public class testDashboardIntegration extends ActivityInstrumentationTestCase2<D
}
private void showAbout() {
- String menu_item = solo.getString(R.string.about);
- solo.clickOnMenuItem(menu_item);
-
+ clickAbout();
String text_unique_to_about = solo.getString(R.string.repository_url_text);
solo.waitForText(text_unique_to_about);
}
- public void testSwitchProvider() {
- tapSwitchProvider();
- solo.goBack();
- }
-
- private void tapSwitchProvider() {
- solo.clickOnMenuItem(solo.getString(R.string.switch_provider_menu_option));
- solo.waitForActivity(ConfigurationWizard.class);
- }
-
- public void testEveryProvider() {
- changeProvider("demo.bitmask.net");
- connectVpn();
- disconnectVpn();
-
- changeProvider("riseup.net");
- connectVpn();
- disconnectVpn();
-
- changeProvider("calyx.net");
- connectVpn();
- disconnectVpn();
- }
-
- private void changeProvider(String provider) {
- tapSwitchProvider();
- solo.clickOnText(provider);
- useRegistered();
- solo.waitForText("Downloading VPN certificate");
- assertDisconnected();
- }
-
- private void connectVpn() {
- Switch vpn_switch = (Switch)solo.getView(R.id.eipSwitch);
- assertFalse(vpn_switch.isChecked());
-
- solo.clickOnView(vpn_switch);
- turningEipOn();
- }
-
- private void disconnectVpn() {
- Switch vpn_switch = (Switch)solo.getView(R.id.eipSwitch);
- assertTrue(vpn_switch.isChecked());
-
- solo.clickOnView(vpn_switch);
- solo.clickOnText("Yes");
- turningEipOff();
-
- }
-
- private void useRegistered() {
- String text = solo.getString(R.string.signup_or_login_button);
- clickAndWaitForDashboard(text);
- login();
+ private void clickAbout() {
+ String menu_item = solo.getString(R.string.about);
+ solo.clickOnMenuItem(menu_item);
}
- private void clickAndWaitForDashboard(String click_text) {
- solo.clickOnText(click_text);
- assertTrue(solo.waitForActivity(Dashboard.class, 5000));
+ private void turnNetworkOff() {
+ ConnectionManager.setMobileDataEnabled(false, context);
+ if (!solo.waitForText(getActivity().getString(R.string.eip_state_not_connected), 1, 15 * 1000))
+ fail();
}
- private void login() {
- long milliseconds_to_log_in = 40 * 1000;
- logIn("parmegvtest10", "holahola2");
- solo.waitForDialogToClose(milliseconds_to_log_in);
- assertSuccessfulLogin();
+ private void restartAdbServer() {
+ runAdbCommand("kill-server");
+ runAdbCommand("start-server");
}
/*public void testReboot() {
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java
new file mode 100644
index 00000000..7e791d16
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testUserStatusFragment.java
@@ -0,0 +1,31 @@
+package se.leap.bitmaskclient.test;
+
+public class testUserStatusFragment extends BaseTestDashboard {
+
+ public final String TAG = testUserStatusFragment.class.getName();
+
+ private final String provider = "demo.bitmask.net";
+ private final String test_username = "parmegvtest1";
+ private final String test_password = " S_Zw3'-";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ changeProviderAndLogIn(provider);
+ user_status_controller.clickUserSessionButton();
+ user_status_controller.assertLoggedOut();
+ }
+
+ public void testLogInAndOut() {
+ user_status_controller.clickUserSessionButton();
+ user_status_controller.logIn(test_username, test_password);
+ user_status_controller.logOut();
+ }
+
+ public void testFailedLogIn() {
+ user_status_controller.clickUserSessionButton();
+ user_status_controller.logIn(test_username, TAG);
+ if(!user_status_controller.assertErrorLogInDialogAppears())
+ throw new IllegalStateException();
+ }
+}
diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java
new file mode 100644
index 00000000..d23be601
--- /dev/null
+++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/testVpnFragment.java
@@ -0,0 +1,87 @@
+package se.leap.bitmaskclient.test;
+
+public class testVpnFragment extends BaseTestDashboard {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ Screenshot.initialize(solo);
+ }
+
+ /**
+ * This test will fail if Android does not trust VPN connection.
+ * I cannot automate that dialog.
+ */
+ public void testOnOffOpenVpn() {
+ Screenshot.take("Initial UI");
+ vpn_controller.clickVpnButton();
+ Screenshot.setTimeToSleep(5);
+ Screenshot.takeWithSleep("Turning VPN on");
+ vpn_controller.turningEipOn();
+ Screenshot.setTimeToSleep(0.5);
+ Screenshot.takeWithSleep("VPN turned on");
+
+ vpn_controller.clickVpnButton();
+ vpn_controller.turningEipOff();
+ Screenshot.take("VPN turned off");
+
+ vpn_controller.clickVpnButton();
+ vpn_controller.turningEipOn();
+
+ vpn_controller.clickVpnButton();
+ vpn_controller.turningEipOff();
+
+ /*clickVpnButton();;
+ turningEipOn();
+
+ turnNetworkOff();
+ restartAdbServer(); // This doesn't work
+ */
+
+ }
+
+ /**
+ * Run only if the trust this app dialog has not been checked.
+ * You must pay attention to the screen, because you need to cancel de dialog twice (block vpn and normal vpn)
+ */
+ public void testOnFailed() {
+ /* TODO Do not rely on the Android's vpn trust dialog
+ vpn_controller.clickVpnButton();
+ assertTrue("Have you checked the trust vpn dialog?", solo.waitForActivity(LogWindow.class));
+ solo.goBack();
+ assertTrue(vpn_controller.iconShowsDisconnected());
+ */
+ }
+
+ public void testVpnEveryProvider() {
+ testDemoBitmaskNet();
+ testRiseupNet();
+ testCalyxNet();
+ }
+
+ private void testDemoBitmaskNet() {
+ testProvider("demo.bitmask.net");
+ }
+
+ private void testRiseupNet() {
+ testProvider("riseup.net");
+ }
+
+ private void testCalyxNet() {
+ testProvider("calyx.net");
+ }
+
+ private void testProvider(String provider) {
+ changeProviderAndLogIn(provider);
+ vpn_controller.sleepSeconds(1);
+ vpn_controller.turnVpnOndAndOff(provider);
+ vpn_controller.sleepSeconds(1);
+ }
+
+ public void testVpnIconIsDisplayed() {
+ assertTrue(isShownWithinConfinesOfVisibleScreen(vpn_controller.getVpnWholeIcon()));
+ }
+ public void testVpnButtonIsDisplayed() {
+ assertTrue(isShownWithinConfinesOfVisibleScreen(vpn_controller.getVpnButton()));
+ }
+}
diff --git a/app/src/debug/AndroidManifest.xml b/app/src/insecure/AndroidManifest.xml
index 523a7ec5..523a7ec5 100644
--- a/app/src/debug/AndroidManifest.xml
+++ b/app/src/insecure/AndroidManifest.xml
diff --git a/app/src/debug/assets/urls/cdev.bitmask.net.url b/app/src/insecure/assets/urls/cdev.bitmask.net.url
index 4ceca5ee..4ceca5ee 100644
--- a/app/src/debug/assets/urls/cdev.bitmask.net.url
+++ b/app/src/insecure/assets/urls/cdev.bitmask.net.url
diff --git a/app/src/debug/assets/urls/dev.bitmask.net.url b/app/src/insecure/assets/urls/dev.bitmask.net.url
index a1e53f69..5d4ae485 100644
--- a/app/src/debug/assets/urls/dev.bitmask.net.url
+++ b/app/src/insecure/assets/urls/dev.bitmask.net.url
@@ -1,3 +1,3 @@
-{
- "main_url" : "https://dev.bitmask.net/"
+{
+ "main_url" : "https://dev.bitmask.net/"
} \ No newline at end of file
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java b/app/src/insecure/java/se/leap/bitmaskclient/ConfigurationWizard.java
index 59d77d83..2505d37b 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ConfigurationWizard.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/ConfigurationWizard.java
@@ -40,6 +40,7 @@ import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface;
import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
/**
* Activity that builds and shows the list of known available providers.
@@ -97,8 +98,7 @@ public class ConfigurationWizard extends Activity
outState.putInt(PROGRESSBAR_NUMBER, mProgressBar.getProgress());
if (progressbar_description != null)
outState.putString(PROGRESSBAR_TEXT, progressbar_description.getText().toString());
- if (selected_provider != null)
- outState.putParcelable(Provider.KEY, selected_provider);
+ outState.putParcelable(Provider.KEY, selected_provider);
super.onSaveInstanceState(outState);
}
@@ -125,8 +125,7 @@ public class ConfigurationWizard extends Activity
progress = savedInstanceState.getInt(PROGRESSBAR_NUMBER, -1);
if (fragment_manager.findFragmentByTag(ProviderDetailFragment.TAG) == null && setting_up_provider) {
- if (selected_provider != null)
- onItemSelectedUi(selected_provider);
+ onItemSelectedUi();
if (progress > 0)
mProgressBar.setProgress(progress);
}
@@ -166,8 +165,7 @@ public class ConfigurationWizard extends Activity
}
private void setUpProviderAPIResultReceiver() {
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
+ providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();
IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
@@ -196,8 +194,6 @@ public class ConfigurationWizard extends Activity
mProgressBar.incrementProgressBy(1);
hideProgressBar();
- setResult(RESULT_OK);
-
showProviderDetails();
}
} else if (resultCode == ProviderAPI.PROVIDER_NOK) {
@@ -205,8 +201,6 @@ public class ConfigurationWizard extends Activity
preferences.edit().remove(Provider.KEY).apply();
setting_up_provider = false;
- setResult(RESULT_CANCELED, mConfigState);
-
String reason_to_fail = resultData.getString(ProviderAPI.ERRORS);
showDownloadFailedDialog(reason_to_fail);
} else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
@@ -214,13 +208,10 @@ public class ConfigurationWizard extends Activity
hideProgressBar();
showProviderDetails();
-
- setResult(RESULT_OK);
} else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
hideProgressBar();
cancelSettingUpProvider();
Toast.makeText(getApplicationContext(), R.string.provider_problem, Toast.LENGTH_LONG).show();
- setResult(RESULT_CANCELED, mConfigState);
} else if (resultCode == AboutActivity.VIEWED) {
// Do nothing, right now
// I need this for CW to wait for the About activity to end before going back to Dashboard.
@@ -231,20 +222,18 @@ public class ConfigurationWizard extends Activity
void onItemSelected(int position) {
//TODO Code 2 pane view
selected_provider = adapter.getItem(position);
- onItemSelectedLogic(selected_provider);
- onItemSelectedUi(selected_provider);
+ onItemSelectedLogic();
+ onItemSelectedUi();
}
- private void onItemSelectedLogic(Provider selected_provider) {
- boolean danger_on = true;
- if (preferences.contains(ProviderItem.DANGER_ON))
- danger_on = preferences.getBoolean(ProviderItem.DANGER_ON, false);
- setUpProvider(selected_provider.mainUrl(), danger_on);
+ private void onItemSelectedLogic() {
+ boolean danger_on = preferences.getBoolean(ProviderItem.DANGER_ON, true);
+ setUpProvider(danger_on);
}
- private void onItemSelectedUi(Provider provider) {
+ private void onItemSelectedUi() {
startProgressBar();
- adapter.hideAllBut(adapter.indexOf(provider));
+ adapter.hideAllBut(adapter.indexOf(selected_provider));
}
@Override
@@ -383,21 +372,21 @@ public class ConfigurationWizard extends Activity
private void autoSelectProvider(Provider provider, boolean danger_on) {
preferences.edit().putBoolean(ProviderItem.DANGER_ON, danger_on).apply();
selected_provider = provider;
- onItemSelectedLogic(selected_provider);
- onItemSelectedUi(selected_provider);
+ onItemSelectedLogic();
+ onItemSelectedUi();
}
/**
* Asks ProviderAPI to download a new provider.json file
*
- * @param provider_main_url
* @param danger_on tells if HTTPS client should bypass certificate errors
*/
- public void setUpProvider(URL provider_main_url, boolean danger_on) {
+ public void setUpProvider(boolean danger_on) {
Intent provider_API_command = new Intent(this, ProviderAPI.class);
Bundle parameters = new Bundle();
- parameters.putString(Provider.MAIN_URL, provider_main_url.toString());
+ parameters.putString(Provider.MAIN_URL, selected_provider.mainUrl().getUrl().toString());
parameters.putBoolean(ProviderItem.DANGER_ON, danger_on);
+ parameters.putString(Provider.CA_CERT_FINGERPRINT, selected_provider.certificatePin());
provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER);
provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
diff --git a/app/src/debug/java/se/leap/bitmaskclient/NewProviderDialog.java b/app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java
index c1426708..c1426708 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/NewProviderDialog.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/NewProviderDialog.java
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java
index 0b24e1c9..2d7e13fe 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -18,9 +18,14 @@ package se.leap.bitmaskclient;
import android.app.*;
import android.content.*;
+import android.content.res.*;
import android.os.*;
import android.util.*;
+import org.apache.http.client.*;
+import org.json.*;
+import org.thoughtcrime.ssl.pinning.util.*;
+
import java.io.*;
import java.math.*;
import java.net.*;
@@ -31,11 +36,11 @@ import java.util.*;
import javax.net.ssl.*;
-import org.apache.http.client.*;
-import org.json.*;
-
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
+import se.leap.bitmaskclient.ProviderListContent.*;
import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
+import se.leap.bitmaskclient.userstatus.User;
+import se.leap.bitmaskclient.userstatus.UserStatus;
/**
* Implements HTTP api methods used to manage communications with the provider server.
@@ -87,6 +92,8 @@ public class ProviderAPI extends IntentService {
private static boolean go_ahead = true;
private static SharedPreferences preferences;
private static String provider_api_url;
+ private static String provider_ca_cert_fingerprint;
+ private Resources resources;
public static void stop() {
go_ahead = false;
@@ -100,7 +107,9 @@ public class ProviderAPI extends IntentService {
public void onCreate() {
super.onCreate();
+
preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE);
+ resources = getResources();
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
}
@@ -121,7 +130,7 @@ public class ProviderAPI extends IntentService {
final ResultReceiver receiver = command.getParcelableExtra(RECEIVER_KEY);
String action = command.getAction();
Bundle parameters = command.getBundleExtra(PARAMETERS);
- if (provider_api_url == null) {
+ if (provider_api_url == null && preferences.contains(Provider.KEY)) {
try {
JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "no provider"));
provider_api_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION);
@@ -133,15 +142,13 @@ public class ProviderAPI extends IntentService {
if (action.equalsIgnoreCase(SET_UP_PROVIDER)) {
Bundle result = setUpProvider(parameters);
- if (go_ahead) {
- if (result.getBoolean(RESULT_KEY)) {
- receiver.send(PROVIDER_OK, result);
- } else {
- receiver.send(PROVIDER_NOK, result);
- }
+ if (result.getBoolean(RESULT_KEY)) {
+ receiver.send(PROVIDER_OK, result);
+ } else {
+ receiver.send(PROVIDER_NOK, result);
}
} else if (action.equalsIgnoreCase(SIGN_UP)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.SIGNING_UP);
+ UserStatus.updateStatus(UserStatus.SessionStatus.SIGNING_UP, resources);
Bundle result = tryToRegister(parameters);
if (result.getBoolean(RESULT_KEY)) {
receiver.send(SUCCESSFUL_SIGNUP, result);
@@ -149,23 +156,24 @@ public class ProviderAPI extends IntentService {
receiver.send(FAILED_SIGNUP, result);
}
} else if (action.equalsIgnoreCase(LOG_IN)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_IN, resources);
Bundle result = tryToAuthenticate(parameters);
if (result.getBoolean(RESULT_KEY)) {
receiver.send(SUCCESSFUL_LOGIN, result);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_IN, resources);
} else {
receiver.send(FAILED_LOGIN, result);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.NOT_LOGGED_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.NOT_LOGGED_IN, resources);
}
} else if (action.equalsIgnoreCase(LOG_OUT)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_OUT);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_OUT, resources);
if (logOut()) {
receiver.send(SUCCESSFUL_LOGOUT, Bundle.EMPTY);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_OUT);
+ android.util.Log.d(TAG, "Logged out, notifying user status");
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_OUT, resources);
} else {
receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.DIDNT_LOG_OUT);
+ UserStatus.updateStatus(UserStatus.SessionStatus.DIDNT_LOG_OUT, resources);
}
} else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
if (updateVpnCertificate()) {
@@ -420,6 +428,8 @@ public class ProviderAPI extends IntentService {
InputStream is = null;
urlConnection = (HttpsURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod(request_method);
+ String locale = Locale.getDefault().getLanguage() + Locale.getDefault().getCountry();
+ urlConnection.setRequestProperty("Accept-Language", locale);
urlConnection.setChunkedStreamingMode(0);
urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory());
@@ -506,15 +516,20 @@ public class ProviderAPI extends IntentService {
int progress = 0;
Bundle current_download = new Bundle();
- if (task != null && task.containsKey(ProviderItem.DANGER_ON) && task.containsKey(Provider.MAIN_URL)) {
- last_danger_on = task.getBoolean(ProviderItem.DANGER_ON);
- last_provider_main_url = task.getString(Provider.MAIN_URL);
+ if (task != null) {
+ last_danger_on = task.containsKey(ProviderItem.DANGER_ON) && task.getBoolean(ProviderItem.DANGER_ON);
+ last_provider_main_url = task.containsKey(Provider.MAIN_URL) ?
+ task.getString(Provider.MAIN_URL) :
+ "";
+ provider_ca_cert_fingerprint = task.containsKey(Provider.CA_CERT_FINGERPRINT) ?
+ task.getString(Provider.CA_CERT_FINGERPRINT) :
+ "";
CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false;
go_ahead = true;
}
if (!PROVIDER_JSON_DOWNLOADED)
- current_download = getAndSetProviderJson(last_provider_main_url, last_danger_on);
+ current_download = getAndSetProviderJson(last_provider_main_url, last_danger_on, provider_ca_cert_fingerprint);
if (PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
broadcastProgress(progress++);
PROVIDER_JSON_DOWNLOADED = true;
@@ -603,11 +618,15 @@ public class ProviderAPI extends IntentService {
return hexData.toString();
}
- private Bundle getAndSetProviderJson(String provider_main_url, boolean danger_on) {
+ private Bundle getAndSetProviderJson(String provider_main_url, boolean danger_on, String provider_ca_cert_fingerprint) {
Bundle result = new Bundle();
if (go_ahead) {
- String provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json", danger_on);
+ String provider_dot_json_string;
+ if(provider_ca_cert_fingerprint.isEmpty())
+ provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json", danger_on);
+ else
+ provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json", danger_on, provider_ca_cert_fingerprint);
try {
JSONObject provider_json = new JSONObject(provider_dot_json_string);
@@ -673,6 +692,29 @@ public class ProviderAPI extends IntentService {
return error_message;
}
+ private String downloadWithCommercialCA(String url_string, boolean danger_on, String ca_cert_fingerprint) {
+ String result = "";
+
+ int seconds_of_timeout = 2;
+ String[] pins = new String[] {ca_cert_fingerprint};
+ try {
+ URL url = new URL(url_string);
+ HttpsURLConnection connection = PinningHelper.getPinnedHttpsURLConnection(getApplicationContext(), pins, url);
+ connection.setConnectTimeout(seconds_of_timeout * 1000);
+ if (!LeapSRPSession.getToken().isEmpty())
+ connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken());
+ result = new Scanner(connection.getInputStream()).useDelimiter("\\A").next();
+ } catch (IOException e) {
+ if(e instanceof SSLHandshakeException) {
+ result = danger_on ? downloadWithoutCA(url_string) :
+ formatErrorMessage(R.string.error_security_pinnedcertificate);
+ } else
+ result = formatErrorMessage(R.string.error_io_exception_user_message);
+ }
+
+ return result;
+ }
+
/**
* Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider.
* <p/>
@@ -691,6 +733,7 @@ public class ProviderAPI extends IntentService {
try {
provider_url = new URL(string_url);
URLConnection url_connection = provider_url.openConnection();
+
url_connection.setConnectTimeout(seconds_of_timeout * 1000);
if (!LeapSRPSession.getToken().isEmpty())
url_connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken());
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderDetailFragment.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailFragment.java
index bd21f91e..6d9a16cd 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderDetailFragment.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailFragment.java
@@ -1,111 +1,111 @@
-package se.leap.bitmaskclient;
-
-import org.json.*;
-
-import se.leap.bitmaskclient.eip.*;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-
-import android.app.*;
-import android.content.*;
-import android.os.*;
-import android.view.*;
-import android.widget.*;
-
-public class ProviderDetailFragment extends DialogFragment {
-
- final public static String TAG = "providerDetailFragment";
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- try {
-
- LayoutInflater inflater = getActivity().getLayoutInflater();
- View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null);
-
- JSONObject provider_json = new JSONObject(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, getActivity().MODE_PRIVATE).getString(Provider.KEY, ""));
-
- final TextView domain = (TextView) provider_detail_view.findViewById(R.id.provider_detail_domain);
- domain.setText(provider_json.getString(Provider.DOMAIN));
- final TextView name = (TextView) provider_detail_view.findViewById(R.id.provider_detail_name);
- name.setText(provider_json.getJSONObject(Provider.NAME).getString("en"));
- final TextView description = (TextView) provider_detail_view.findViewById(R.id.provider_detail_description);
- description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en"));
-
- builder.setView(provider_detail_view);
- builder.setTitle(R.string.provider_details_fragment_title);
-
- if (anon_allowed(provider_json)) {
- builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.use_anonymously();
- }
- });
- }
-
- if (registration_allowed(provider_json)) {
- builder.setNegativeButton(R.string.signup_or_login_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.login();
- }
- });
- }
-
- return builder.create();
- } catch (JSONException e) {
- return null;
- }
- }
-
- private boolean anon_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(Constants.ALLOWED_ANON) && service_description.getBoolean(Constants.ALLOWED_ANON);
- } catch (JSONException e) {
- return false;
- }
- }
-
- private boolean registration_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION);
- } catch (JSONException e) {
- return false;
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- SharedPreferences.Editor editor = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit();
- editor.remove(Provider.KEY).remove(ProviderItem.DANGER_ON).remove(Constants.ALLOWED_ANON).remove(Constants.KEY).commit();
- interface_with_configuration_wizard.showAllProviders();
- }
-
- public static DialogFragment newInstance() {
- ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment();
- return provider_detail_fragment;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString()
- + " must implement LogInDialogListener");
- }
- }
-
- public interface ProviderDetailFragmentInterface {
- public void login();
-
- public void use_anonymously();
-
- public void showAllProviders();
- }
-
- ProviderDetailFragmentInterface interface_with_configuration_wizard;
-}
+package se.leap.bitmaskclient;
+
+import org.json.*;
+
+import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
+
+import android.app.*;
+import android.content.*;
+import android.os.*;
+import android.view.*;
+import android.widget.*;
+
+public class ProviderDetailFragment extends DialogFragment {
+
+ final public static String TAG = "providerDetailFragment";
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ try {
+
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null);
+
+ JSONObject provider_json = new JSONObject(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, getActivity().MODE_PRIVATE).getString(Provider.KEY, ""));
+
+ final TextView domain = (TextView) provider_detail_view.findViewById(R.id.provider_detail_domain);
+ domain.setText(provider_json.getString(Provider.DOMAIN));
+ final TextView name = (TextView) provider_detail_view.findViewById(R.id.provider_detail_name);
+ name.setText(provider_json.getJSONObject(Provider.NAME).getString("en"));
+ final TextView description = (TextView) provider_detail_view.findViewById(R.id.provider_detail_description);
+ description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en"));
+
+ builder.setView(provider_detail_view);
+ builder.setTitle(R.string.provider_details_fragment_title);
+
+ if (anon_allowed(provider_json)) {
+ builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ interface_with_configuration_wizard.use_anonymously();
+ }
+ });
+ }
+
+ if (registration_allowed(provider_json)) {
+ builder.setNegativeButton(R.string.signup_or_login_button, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ interface_with_configuration_wizard.login();
+ }
+ });
+ }
+
+ return builder.create();
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ private boolean anon_allowed(JSONObject provider_json) {
+ try {
+ JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
+ return service_description.has(Constants.ALLOWED_ANON) && service_description.getBoolean(Constants.ALLOWED_ANON);
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ private boolean registration_allowed(JSONObject provider_json) {
+ try {
+ JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
+ return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION);
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ SharedPreferences.Editor editor = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit();
+ editor.remove(Provider.KEY).remove(ProviderItem.DANGER_ON).remove(Constants.ALLOWED_ANON).remove(Constants.KEY).commit();
+ interface_with_configuration_wizard.showAllProviders();
+ }
+
+ public static DialogFragment newInstance() {
+ ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment();
+ return provider_detail_fragment;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(activity.toString()
+ + " must implement LogInDialogListener");
+ }
+ }
+
+ public interface ProviderDetailFragmentInterface {
+ public void login();
+
+ public void use_anonymously();
+
+ public void showAllProviders();
+ }
+
+ ProviderDetailFragmentInterface interface_with_configuration_wizard;
+}
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderListContent.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java
index 0a05e839..c8dfc092 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderListContent.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java
@@ -1,82 +1,82 @@
-/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package se.leap.bitmaskclient;
-
-import java.util.*;
-import java.net.*;
-
-/**
- * Models the provider list shown in the ConfigurationWizard.
- *
- * @author parmegv
- */
-public class ProviderListContent {
-
- public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>();
-
- public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>();
-
- /**
- * Adds a new provider item to the end of the items map, and to the items list.
- *
- * @param item
- */
- public static void addItem(ProviderItem item) {
- ITEMS.add(item);
- ITEM_MAP.put(String.valueOf(ITEMS.size()), item);
- }
-
- public static void removeItem(ProviderItem item) {
- ITEMS.remove(item);
- ITEM_MAP.remove(item);
- }
-
- /**
- * A provider item.
- */
- public static class ProviderItem {
- final public static String CUSTOM = "custom";
- final public static String DANGER_ON = "danger_on";
- private String provider_main_url;
- private String name;
-
- /**
- * @param name of the provider
- * @param provider_main_url used to download provider.json file of the provider
- */
- public ProviderItem(String name, String provider_main_url) {
- this.name = name;
- this.provider_main_url = provider_main_url;
- }
-
- public String name() {
- return name;
- }
-
- public String providerMainUrl() {
- return provider_main_url;
- }
-
- public String domain() {
- try {
- return new URL(provider_main_url).getHost();
- } catch (MalformedURLException e) {
- return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", "");
- }
- }
- }
-}
+/**
+ * Copyright (c) 2013 LEAP Encryption Access Project and contributers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package se.leap.bitmaskclient;
+
+import java.util.*;
+import java.net.*;
+
+/**
+ * Models the provider list shown in the ConfigurationWizard.
+ *
+ * @author parmegv
+ */
+public class ProviderListContent {
+
+ public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>();
+
+ public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>();
+
+ /**
+ * Adds a new provider item to the end of the items map, and to the items list.
+ *
+ * @param item
+ */
+ public static void addItem(ProviderItem item) {
+ ITEMS.add(item);
+ ITEM_MAP.put(String.valueOf(ITEMS.size()), item);
+ }
+
+ public static void removeItem(ProviderItem item) {
+ ITEMS.remove(item);
+ ITEM_MAP.remove(item);
+ }
+
+ /**
+ * A provider item.
+ */
+ public static class ProviderItem {
+ final public static String CUSTOM = "custom";
+ final public static String DANGER_ON = "danger_on";
+ private String provider_main_url;
+ private String name;
+
+ /**
+ * @param name of the provider
+ * @param provider_main_url used to download provider.json file of the provider
+ */
+ public ProviderItem(String name, String provider_main_url) {
+ this.name = name;
+ this.provider_main_url = provider_main_url;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String providerMainUrl() {
+ return provider_main_url;
+ }
+
+ public String domain() {
+ try {
+ return new URL(provider_main_url).getHost();
+ } catch (MalformedURLException e) {
+ return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", "");
+ }
+ }
+ }
+}
diff --git a/app/src/debug/res/layout-xlarge/new_provider_dialog.xml b/app/src/insecure/res/layout-xlarge/new_provider_dialog.xml
index fc7d84ab..fc7d84ab 100644
--- a/app/src/debug/res/layout-xlarge/new_provider_dialog.xml
+++ b/app/src/insecure/res/layout-xlarge/new_provider_dialog.xml
diff --git a/app/src/debug/res/layout/new_provider_dialog.xml b/app/src/insecure/res/layout/new_provider_dialog.xml
index 19b8f442..19b8f442 100644
--- a/app/src/debug/res/layout/new_provider_dialog.xml
+++ b/app/src/insecure/res/layout/new_provider_dialog.xml
diff --git a/app/src/debug/res/values/strings.xml b/app/src/insecure/res/values/strings.xml
index 3e568115..3e568115 100644
--- a/app/src/debug/res/values/strings.xml
+++ b/app/src/insecure/res/values/strings.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cc31de43..ce89a317 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.leap.bitmaskclient"
- android:versionCode="120"
- android:versionName="0.9.3" >
+ android:versionCode="125"
+ android:versionName="0.9.4" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index 0eb1d99c..90216a70 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -7,8 +7,6 @@ package de.blinkt.openvpn;
import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.R;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
@@ -117,26 +115,29 @@ public class LaunchVPN extends Activity {
}
}
-
+
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==START_VPN_PROFILE) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean showlogwindow = prefs.getBoolean("showlogwindow", true);
-
- if(!mhideLog && showlogwindow)
- showLogWindow();
- new startOpenVpnThread().start();
- } else if (resultCode == Activity.RESULT_CANCELED) {
- // User does not want us to start, so we just vanish
- VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled, ConnectionStatus.LEVEL_NOTCONNECTED);
-
- finish();
+ if(resultCode == Activity.RESULT_OK) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean showLogWindow = prefs.getBoolean("showlogwindow", true);
+
+ if(!mhideLog && showLogWindow)
+ showLogWindow();
+ new startOpenVpnThread().start();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ // User does not want us to start, so we just vanish
+ VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
+ ConnectionStatus.LEVEL_NOTCONNECTED);
+
+ finish();
+ }
}
}
-
+
void showLogWindow() {
Intent startLW = new Intent(getBaseContext(),LogWindow.class);
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index 4f747d21..43e1b57c 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -7,8 +7,6 @@ package de.blinkt.openvpn;
import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.R;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
@@ -98,7 +96,7 @@ public class VpnProfile implements Serializable, Cloneable {
// variable named wrong and should haven beeen transient
// but needs to keep wrong name to guarante loading of old
// profiles
- public transient boolean profileDleted = false;
+ public transient boolean profileDeleted = false;
public int mAuthenticationType = TYPE_KEYSTORE;
public String mName;
public String mAlias;
@@ -156,7 +154,7 @@ public class VpnProfile implements Serializable, Cloneable {
public boolean mRemoteRandom=false;
public HashSet<String> mAllowedAppsVpn = new HashSet<String>();
public boolean mAllowedAppsVpnAreDisallowed = true;
-
+ public String mProfileCreator;
/* Options no long used in new profiles */
public String mServerName = "openvpn.blinkt.de";
@@ -699,7 +697,11 @@ public class VpnProfile implements Serializable, Cloneable {
protected VpnProfile clone() throws CloneNotSupportedException {
VpnProfile copy = (VpnProfile) super.clone();
copy.mUuid = UUID.randomUUID();
- copy.mConnections = mConnections.clone();
+ copy.mConnections = new Connection[mConnections.length];
+ int i=0;
+ for (Connection conn: mConnections) {
+ copy.mConnections[i++]=conn.clone();
+ }
copy.mAllowedAppsVpn = (HashSet<String>) mAllowedAppsVpn.clone();
return copy;
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
index e525abd5..94ed8a0b 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/CIDRIP.java
@@ -54,6 +54,7 @@ class CIDRIP {
} else {
return false;
}
+
}
static long getInt(String ipaddr) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
index 5f5d486c..232c454b 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
@@ -31,6 +31,9 @@ public class ConfigParser {
public static final String CONVERTED_PROFILE = "converted Profile";
private HashMap<String, Vector<Vector<String>>> options = new HashMap<String, Vector<Vector<String>>>();
private HashMap<String, Vector<String>> meta = new HashMap<String, Vector<String>>();
+ private String auth_user_pass_file;
+ private String crl_verify_file;
+
public void parseConfig(Reader reader) throws IOException, ConfigParseError {
@@ -114,6 +117,14 @@ public class ConfigParser {
}
+ public String getAuthUserPassFile() {
+ return auth_user_pass_file;
+ }
+
+ public String getCrlVerifyFile() {
+ return crl_verify_file;
+ }
+
enum linestate {
initial,
readin_single_quote, reading_quoted, reading_unquoted, done
@@ -572,6 +583,7 @@ public class ConfigParser {
options.put("remotetls", remotetls);
Vector<String> authuser = getOption("auth-user-pass", 0, 1);
+
if (authuser != null) {
if (noauthtypeset) {
np.mAuthenticationType = VpnProfile.TYPE_USERPASS;
@@ -581,12 +593,24 @@ public class ConfigParser {
np.mAuthenticationType = VpnProfile.TYPE_USERPASS_KEYSTORE;
}
if (authuser.size() > 1) {
- // Set option value to password get to embed later.
+ if (!authuser.get(1).startsWith(VpnProfile.INLINE_TAG))
+ auth_user_pass_file = authuser.get(1);
np.mUsername = null;
useEmbbedUserAuth(np, authuser.get(1));
}
}
+ Vector<String> crlfile = getOption("crl-verify", 1, 2);
+ if (crlfile != null) {
+ // If the 'dir' parameter is present just add it as custom option ..
+ np.mCustomConfigOptions += TextUtils.join(" ", crlfile) + "\n";
+ if (crlfile.size() == 2) {
+ // Save the filename for the config converter to add later
+ crl_verify_file = crlfile.get(1);
+ }
+ }
+
+
Pair<Connection, Connection[]> conns = parseConnectionOptions(null);
np.mConnections = conns.second;
@@ -761,6 +785,16 @@ public class ConfigParser {
}
}
+ public static void removeCRLCustomOption(VpnProfile np) {
+ String lines[] = np.mCustomConfigOptions.split("\\r?\\n");
+ Vector<String> keeplines = new Vector<>();
+ for (String l : lines) {
+ if (!l.startsWith("crl-verify "))
+ keeplines.add(l);
+ }
+ np.mCustomConfigOptions = TextUtils.join("\n", keeplines);
+ }
+
private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError {
for (String option : unsupportedOptions)
if (options.containsKey(option))
@@ -772,7 +806,8 @@ public class ConfigParser {
if (options.size() > 0) {
- np.mCustomConfigOptions += "# These Options were found in the config file do not map to config settings:\n";
+ np.mCustomConfigOptions = "# These options found in the config file do not map to config settings:\n"
+ + np.mCustomConfigOptions;
for (Vector<Vector<String>> option : options.values()) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
index 56a574dc..6e9e63c5 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
@@ -38,5 +38,4 @@ public class ICSOpenVPNApplication extends Application {
//ACRA.init(this);
}
}
-
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index 3c1ec064..f9cb9a86 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -16,7 +16,6 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
-import android.net.NetworkRequest;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
@@ -51,8 +50,6 @@ import static de.blinkt.openvpn.core.NetworkSpace.ipAddress;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
-import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED;
-import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NONETWORK;
import se.leap.bitmaskclient.Dashboard;
@@ -65,7 +62,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private static final String RESUME_VPN = "se.leap.bitmaskclient.RESUME_VPN";
private static final int OPENVPN_STATUS = 1;
private static boolean mNotificationAlwaysVisible = false;
- private final Vector<String> mDnslist = new Vector<String>();
+ private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
private final NetworkSpace mRoutesv6 = new NetworkSpace();
private final IBinder mBinder = new LocalBinder();
@@ -84,7 +81,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private String mLastTunCfg;
private String mRemoteGW;
private final Object mProcessLock = new Object();
- private LollipopDeviceStateListener mLollipopDeviceStateListener;
// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
public static String humanReadableByteCount(long bytes, boolean mbit) {
@@ -238,13 +234,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
//ignore exception
- } catch (NoSuchMethodException nsm) {
- VpnStatus.logException(nsm);
- } catch (IllegalArgumentException e) {
- VpnStatus.logException(e);
- } catch (IllegalAccessException e) {
- VpnStatus.logException(e);
- } catch (InvocationTargetException e) {
+ } catch (NoSuchMethodException | IllegalArgumentException |
+ InvocationTargetException | IllegalAccessException e) {
VpnStatus.logException(e);
}
@@ -328,6 +319,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
/* The intent is null when the service has been restarted */
if (intent == null) {
mProfile = ProfileManager.getLastConnectedProfile(this, false);
+ VpnStatus.logInfo(R.string.service_restarted);
/* Got no profile, just stop */
if (mProfile == null) {
@@ -415,7 +407,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
} else {
- HashMap<String, String> env = new HashMap<String, String>();
+ HashMap<String, String> env = new HashMap<>();
processThread = new OpenVPNThread(this, argv, env, nativeLibraryDirectory);
}
@@ -431,7 +423,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
ProfileManager.setConnectedVpnProfile(this, mProfile);
/* TODO: At the moment we have no way to handle asynchronous PW input
- * Fixing will also allow to handle challenge/responsee authentication */
+ * Fixing will also allow to handle challenge/response authentication */
if (mProfile.needUserPWInput(true) != 0)
return START_NOT_STICKY;
@@ -442,17 +434,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
try {
Class cl = Class.forName("de.blinkt.openvpn.core.OpenVPNThreadv3");
return (OpenVPNManagement) cl.getConstructor(OpenVPNService.class, VpnProfile.class).newInstance(this, mProfile);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
+ } catch (IllegalArgumentException | InstantiationException | InvocationTargetException |
+ NoSuchMethodException | ClassNotFoundException | IllegalAccessException e ) {
e.printStackTrace();
}
return null;
@@ -501,8 +484,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.logInfo(R.string.last_openvpn_tun_config);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN)
- {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN) {
allowAllAFFamilies(builder);
}
@@ -576,6 +558,26 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
}
+ if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mDnslist.size() >= 1) {
+ // Check if the first DNS Server is in the VPN range
+ try {
+ ipAddress dnsServer = new ipAddress(new CIDRIP(mDnslist.get(0), 32), true);
+ boolean dnsIncluded=false;
+ for (ipAddress net : positiveIPv4Routes) {
+ if (net.containsNet(dnsServer)) {
+ dnsIncluded = true;
+ }
+ }
+ if (!dnsIncluded) {
+ String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS add a custom route to your DNS Server (%s) or change to a DNS inside your VPN range", mDnslist.get(0));
+ VpnStatus.logWarning(samsungwarning);
+ }
+ } catch (Exception e) {
+ VpnStatus.logError("Error parsing DNS Server IP: " + mDnslist.get(0));
+ }
+ }
+
+
if (mDomain != null)
builder.addSearchDomain(mDomain);
@@ -616,7 +618,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
try {
//Debug.stopMethodTracing();
ParcelFileDescriptor tun = builder.establish();
- if (tun==null)
+ if (tun == null)
throw new NullPointerException("Android establish() method returned null (Really broken network configuration?)");
return tun;
} catch (Exception e) {
@@ -636,22 +638,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
builder.allowFamily(OsConstants.AF_INET6);
}
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- void removeLollipopCMListener() {
- ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE);
- cm.unregisterNetworkCallback(mLollipopDeviceStateListener);
- mLollipopDeviceStateListener = null;
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- void addLollipopCMListener() {
- ConnectivityManager cm = (ConnectivityManager) getBaseContext().getSystemService(CONNECTIVITY_SERVICE);
- NetworkRequest.Builder nrb = new NetworkRequest.Builder();
-
- mLollipopDeviceStateListener = new LollipopDeviceStateListener();
- cm.registerNetworkCallback(nrb.build(), mLollipopDeviceStateListener);
- }
-
private void addLocalNetworksToRoutes() {
// Add local network interfaces
@@ -667,11 +653,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
intf.startsWith("tun") || intf.startsWith("rmnet"))
continue;
- if (ipAddr==null || netMask == null) {
+ if (ipAddr == null || netMask == null) {
VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes));
continue;
}
-
+
if (ipAddr.equals(mLocalIP.mIp))
continue;
@@ -854,21 +840,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mDisplayBytecount = true;
mConnecttime = System.currentTimeMillis();
lowpriority = true;
- if(mProfile.mPersistTun) {
- NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- ns.cancel(OPENVPN_STATUS);
- return;
- }
- } else if (level == LEVEL_NONETWORK || level == LEVEL_NOTCONNECTED) {
- NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- ns.cancel(OPENVPN_STATUS);
- return;
- } else if (level != LEVEL_NOTCONNECTED && mConnecttime > 0) {
- mDisplayBytecount = false;
- String msg = "Traffic is blocked until the VPN becomes active.";
- String ticker = msg;
- showNotification(msg, ticker, lowpriority , 0, level);
- return;
+ String ns = Context.NOTIFICATION_SERVICE;
+ NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
+ mNotificationManager.cancel(OPENVPN_STATUS);
} else {
mDisplayBytecount = false;
}
@@ -878,8 +852,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
// CONNECTED
// Does not work :(
String msg = getString(resid);
- String ticker = msg;
- showNotification(msg + " " + logmessage, ticker, lowpriority, 0, level);
+ // showNotification(msg + " " + logmessage, msg, lowpriority, 0, level);
}
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
index 1ebc0a57..086cdb44 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
@@ -5,11 +5,15 @@
package de.blinkt.openvpn.core;
-import java.io.FileNotFoundException;
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.preference.PreferenceManager;
+
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.StreamCorruptedException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -17,213 +21,173 @@ import java.util.Set;
import de.blinkt.openvpn.VpnProfile;
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.preference.PreferenceManager;
-
public class ProfileManager {
- private static final String PREFS_NAME = "VPNList";
+ private static final String PREFS_NAME = "VPNList";
+ private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile";
+ private static ProfileManager instance;
+ private static VpnProfile mLastConnectedVpn = null;
+ private HashMap<String, VpnProfile> profiles = new HashMap<>();
+ private static VpnProfile tmpprofile = null;
- private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile";
+ private static VpnProfile get(String key) {
+ if (tmpprofile != null && tmpprofile.getUUIDString().equals(key))
+ return tmpprofile;
+ if (instance == null)
+ return null;
+ return instance.profiles.get(key);
+
+ }
- private static ProfileManager instance;
+ private ProfileManager() {
+ }
+ private static void checkInstance(Context context) {
+ if (instance == null) {
+ instance = new ProfileManager();
+ instance.loadVPNList(context);
+ }
+ }
- private static VpnProfile mLastConnectedVpn=null;
- private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>();
- private static VpnProfile tmpprofile=null;
+ synchronized public static ProfileManager getInstance(Context context) {
+ checkInstance(context);
+ return instance;
+ }
+ public static void setConntectedVpnProfileDisconnected(Context c) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+ Editor prefsedit = prefs.edit();
+ prefsedit.putString(LAST_CONNECTED_PROFILE, null);
+ prefsedit.apply();
- private static VpnProfile get(String key) {
- if (tmpprofile!=null && tmpprofile.getUUIDString().equals(key))
- return tmpprofile;
-
- if(instance==null)
- return null;
- return instance.profiles.get(key);
-
- }
+ }
+ public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+ Editor prefsedit = prefs.edit();
-
- private ProfileManager() { }
-
- private static void checkInstance(Context context) {
- if(instance == null) {
- instance = new ProfileManager();
- instance.loadVPNList(context);
- }
- }
+ prefsedit.putString(LAST_CONNECTED_PROFILE, connectedrofile.getUUIDString());
+ prefsedit.apply();
+ mLastConnectedVpn = connectedrofile;
- synchronized public static ProfileManager getInstance(Context context) {
- checkInstance(context);
- return instance;
- }
-
- public static void setConntectedVpnProfileDisconnected(Context c) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
- Editor prefsedit = prefs.edit();
- prefsedit.putString(LAST_CONNECTED_PROFILE, null);
- prefsedit.apply();
-
- }
+ }
- public static void setConnectedVpnProfile(Context c, VpnProfile connectedrofile) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
- Editor prefsedit = prefs.edit();
-
- prefsedit.putString(LAST_CONNECTED_PROFILE, connectedrofile.getUUIDString());
- prefsedit.apply();
- mLastConnectedVpn=connectedrofile;
-
- }
-
- public static VpnProfile getLastConnectedProfile(Context c, boolean onBoot) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+ public static VpnProfile getLastConnectedProfile(Context c, boolean onBoot) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
- boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false);
+ boolean useStartOnBoot = prefs.getBoolean("restartvpnonboot", false);
if (onBoot && !useStartOnBoot)
return null;
-
- String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
- if(lastConnectedProfile!=null)
- return get(c, lastConnectedProfile);
- else
- return null;
- }
-
-
-
-
- public Collection<VpnProfile> getProfiles() {
- return profiles.values();
- }
-
- public VpnProfile getProfileByName(String name) {
- for (VpnProfile vpnp : profiles.values()) {
- if(vpnp.getName().equals(name)) {
- return vpnp;
- }
- }
- return null;
- }
-
- public void saveProfileList(Context context) {
- SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
- Editor editor = sharedprefs.edit();
- editor.putStringSet("vpnlist", profiles.keySet());
-
- // For reasing I do not understand at all
- // Android saves my prefs file only one time
- // if I remove the debug code below :(
- int counter = sharedprefs.getInt("counter", 0);
- editor.putInt("counter", counter+1);
- editor.apply();
-
- }
-
- public void addProfile(VpnProfile profile) {
- profiles.put(profile.getUUID().toString(),profile);
-
- }
-
- public static void setTemporaryProfile(VpnProfile tmp) {
- ProfileManager.tmpprofile = tmp;
- }
-
-
- public void saveProfile(Context context,VpnProfile profile) {
- // First let basic settings save its state
-
- ObjectOutputStream vpnfile;
- try {
- vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE));
-
- vpnfile.writeObject(profile);
- vpnfile.flush();
- vpnfile.close();
- } catch (FileNotFoundException e) {
- VpnStatus.logException("saving VPN profile", e);
- throw new RuntimeException(e);
- } catch (IOException e) {
- VpnStatus.logException("saving VPN profile", e);
- throw new RuntimeException(e);
- }
- }
-
-
- private void loadVPNList(Context context) {
- profiles = new HashMap<String, VpnProfile>();
- SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
- Set<String> vlist = listpref.getStringSet("vpnlist", null);
- Exception exp =null;
- if(vlist==null){
- vlist = new HashSet<String>();
- }
-
- for (String vpnentry : vlist) {
- try {
- ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
- VpnProfile vp = ((VpnProfile) vpnfile.readObject());
-
- // Sanity check
- if(vp==null || vp.mName==null || vp.getUUID()==null)
- continue;
+ String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
+ if (lastConnectedProfile != null)
+ return get(c, lastConnectedProfile);
+ else
+ return null;
+ }
- vp.upgradeProfile();
- profiles.put(vp.getUUID().toString(), vp);
- } catch (StreamCorruptedException e) {
- exp=e;
- } catch (FileNotFoundException e) {
- exp=e;
- } catch (IOException e) {
- exp=e;
- } catch (ClassNotFoundException e) {
- exp=e;
- }
- if(exp!=null) {
- VpnStatus.logException("Loading VPN List",exp);
- }
- }
- }
+ public Collection<VpnProfile> getProfiles() {
+ return profiles.values();
+ }
+
+ public VpnProfile getProfileByName(String name) {
+ for (VpnProfile vpnp : profiles.values()) {
+ if (vpnp.getName().equals(name)) {
+ return vpnp;
+ }
+ }
+ return null;
+ }
+
+ public void saveProfileList(Context context) {
+ SharedPreferences sharedprefs = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
+ Editor editor = sharedprefs.edit();
+ editor.putStringSet("vpnlist", profiles.keySet());
+
+ // For reasing I do not understand at all
+ // Android saves my prefs file only one time
+ // if I remove the debug code below :(
+ int counter = sharedprefs.getInt("counter", 0);
+ editor.putInt("counter", counter + 1);
+ editor.apply();
+
+ }
+
+ public void addProfile(VpnProfile profile) {
+ profiles.put(profile.getUUID().toString(), profile);
+
+ }
- public int getNumberOfProfiles() {
- return profiles.size();
- }
+ public static void setTemporaryProfile(VpnProfile tmp) {
+ ProfileManager.tmpprofile = tmp;
+ }
+ public void saveProfile(Context context, VpnProfile profile) {
+ ObjectOutputStream vpnfile;
+ try {
+ vpnfile = new ObjectOutputStream(context.openFileOutput((profile.getUUID().toString() + ".vp"), Activity.MODE_PRIVATE));
- public void removeProfile(Context context,VpnProfile profile) {
- String vpnentry = profile.getUUID().toString();
- profiles.remove(vpnentry);
- saveProfileList(context);
- context.deleteFile(vpnentry + ".vp");
- if(mLastConnectedVpn==profile)
- mLastConnectedVpn=null;
-
- }
+ vpnfile.writeObject(profile);
+ vpnfile.flush();
+ vpnfile.close();
+ } catch (IOException e) {
+ VpnStatus.logException("saving VPN profile", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ private void loadVPNList(Context context) {
+ profiles = new HashMap<>();
+ SharedPreferences listpref = context.getSharedPreferences(PREFS_NAME, Activity.MODE_PRIVATE);
+ Set<String> vlist = listpref.getStringSet("vpnlist", null);
+ if (vlist == null) {
+ vlist = new HashSet<>();
+ }
+
+ for (String vpnentry : vlist) {
+ try {
+ ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
+ VpnProfile vp = ((VpnProfile) vpnfile.readObject());
+
+ // Sanity check
+ if (vp == null || vp.mName == null || vp.getUUID() == null)
+ continue;
+
+ vp.upgradeProfile();
+ profiles.put(vp.getUUID().toString(), vp);
+ } catch (IOException | ClassNotFoundException e) {
+ VpnStatus.logException("Loading VPN List", e);
+ }
+ }
+ }
- public static VpnProfile get(Context context, String profileUUID) {
- checkInstance(context);
- return get(profileUUID);
- }
+ public void removeProfile(Context context, VpnProfile profile) {
+ String vpnentry = profile.getUUID().toString();
+ profiles.remove(vpnentry);
+ saveProfileList(context);
+ context.deleteFile(vpnentry + ".vp");
+ if (mLastConnectedVpn == profile)
+ mLastConnectedVpn = null;
+ }
+ public static VpnProfile get(Context context, String profileUUID) {
+ checkInstance(context);
+ return get(profileUUID);
+ }
- public static VpnProfile getLastConnectedVpn() {
- return mLastConnectedVpn;
- }
+ public static VpnProfile getLastConnectedVpn() {
+ return mLastConnectedVpn;
+ }
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
index 73ed05bc..47cb633c 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java
@@ -8,7 +8,6 @@ package de.blinkt.openvpn.core;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.os.Build;
import java.io.File;
@@ -67,14 +66,14 @@ public class VPNLaunchHelper {
public static String[] buildOpenvpnArgv(Context c) {
- Vector<String> args = new Vector<String>();
+ Vector<String> args = new Vector<>();
// Add fixed paramenters
//args.add("/data/data/de.blinkt.openvpn/lib/openvpn");
args.add(writeMiniVPN(c));
args.add("--config");
- args.add(c.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE);
+ args.add(getConfigFilePath(c));
return args.toArray(new String[args.size()]);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
index ffc8097d..62a60643 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
@@ -6,6 +6,7 @@
package de.blinkt.openvpn.core;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -14,10 +15,10 @@ import android.content.pm.Signature;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import se.leap.bitmaskclient.R;
+import android.text.TextUtils;
import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
+import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.MessageDigest;
@@ -32,28 +33,30 @@ import java.util.Locale;
import java.util.UnknownFormatConversionException;
import java.util.Vector;
+import se.leap.bitmaskclient.R;
+
public class VpnStatus {
- public static LinkedList<LogItem> logbuffer;
+ public static LinkedList<LogItem> logbuffer;
- private static Vector<LogListener> logListener;
- private static Vector<StateListener> stateListener;
- private static Vector<ByteCountListener> byteCountListener;
+ private static Vector<LogListener> logListener;
+ private static Vector<StateListener> stateListener;
+ private static Vector<ByteCountListener> byteCountListener;
- private static String mLaststatemsg="";
+ private static String mLaststatemsg = "";
- private static String mLaststate = "NOPROCESS";
+ private static String mLaststate = "NOPROCESS";
- private static int mLastStateresid=R.string.state_noprocess;
+ private static int mLastStateresid = R.string.state_noprocess;
- private static long mlastByteCount[]={0,0,0,0};
+ private static long mlastByteCount[] = {0, 0, 0, 0};
- public static void logException(LogLevel ll, String context, Exception e) {
+ public static void logException(LogLevel ll, String context, Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
LogItem li;
- if (context !=null) {
+ if (context != null) {
li = new LogItem(ll, R.string.unhandled_exception_context, e.getMessage(), sw.toString(), context);
} else {
li = new LogItem(ll, R.string.unhandled_exception, e.getMessage(), sw.toString());
@@ -71,18 +74,16 @@ public class VpnStatus {
private static final int MAXLOGENTRIES = 1000;
- public static final String MANAGMENT_PREFIX = "M:";
-
public enum ConnectionStatus {
LEVEL_CONNECTED,
LEVEL_VPNPAUSED,
LEVEL_CONNECTING_SERVER_REPLIED,
LEVEL_CONNECTING_NO_SERVER_REPLY_YET,
LEVEL_NONETWORK,
- LEVEL_NOTCONNECTED,
- LEVEL_AUTH_FAILED,
- LEVEL_WAITING_FOR_USER_INPUT,
- UNKNOWN_LEVEL
+ LEVEL_NOTCONNECTED,
+ LEVEL_AUTH_FAILED,
+ LEVEL_WAITING_FOR_USER_INPUT,
+ UNKNOWN_LEVEL
}
public enum LogLevel {
@@ -93,6 +94,7 @@ public class VpnStatus {
DEBUG(4);
protected int mValue;
+
LogLevel(int value) {
mValue = value;
}
@@ -103,59 +105,64 @@ public class VpnStatus {
public static LogLevel getEnumByValue(int value) {
switch (value) {
- case 1: return INFO;
- case 2: return ERROR;
- case 3: return WARNING;
- case 4: return DEBUG;
- default: return null;
+ case 1:
+ return INFO;
+ case 2:
+ return ERROR;
+ case 3:
+ return WARNING;
+ case 4:
+ return DEBUG;
+ default:
+ return null;
}
}
}
// keytool -printcert -jarfile de.blinkt.openvpn_85.apk
- public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109};
- public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43};
- public static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57};
+ public static final byte[] officalkey = {-58, -42, -44, -106, 90, -88, -87, -88, -52, -124, 84, 117, 66, 79, -112, -111, -46, 86, -37, 109};
+ public static final byte[] officaldebugkey = {-99, -69, 45, 71, 114, -116, 82, 66, -99, -122, 50, -70, -56, -111, 98, -35, -65, 105, 82, 43};
+ public static final byte[] amazonkey = {-116, -115, -118, -89, -116, -112, 120, 55, 79, -8, -119, -23, 106, -114, -85, -56, -4, 105, 26, -57};
public static final byte[] fdroidkey = {-92, 111, -42, -46, 123, -96, -60, 79, -27, -31, 49, 103, 11, -54, -68, -27, 17, 2, 121, 104};
- private static ConnectionStatus mLastLevel=ConnectionStatus.LEVEL_NOTCONNECTED;
+ private static ConnectionStatus mLastLevel = ConnectionStatus.LEVEL_NOTCONNECTED;
- static {
- logbuffer = new LinkedList<LogItem>();
- logListener = new Vector<VpnStatus.LogListener>();
- stateListener = new Vector<VpnStatus.StateListener>();
- byteCountListener = new Vector<VpnStatus.ByteCountListener>();
- logInformation();
- }
+ static {
+ logbuffer = new LinkedList<>();
+ logListener = new Vector<>();
+ stateListener = new Vector<>();
+ byteCountListener = new Vector<>();
+ logInformation();
+ }
- public static class LogItem implements Parcelable {
+ public static class LogItem implements Parcelable {
- private Object [] mArgs = null;
- private String mMessage = null;
- private int mRessourceId;
- // Default log priority
- LogLevel mLevel = LogLevel.INFO;
- private long logtime = System.currentTimeMillis();
+ private Object[] mArgs = null;
+ private String mMessage = null;
+ private int mRessourceId;
+ // Default log priority
+ LogLevel mLevel = LogLevel.INFO;
+ private long logtime = System.currentTimeMillis();
private int mVerbosityLevel = -1;
- private LogItem(int ressourceId, Object[] args) {
- mRessourceId = ressourceId;
- mArgs = args;
- }
+ private LogItem(int ressourceId, Object[] args) {
+ mRessourceId = ressourceId;
+ mArgs = args;
+ }
public LogItem(LogLevel level, int verblevel, String message) {
- mMessage=message;
+ mMessage = message;
mLevel = level;
mVerbosityLevel = verblevel;
}
@Override
- public int describeContents() {
- return 0;
- }
+ public int describeContents() {
+ return 0;
+ }
@Override
@@ -169,65 +176,65 @@ public class VpnStatus {
dest.writeLong(logtime);
}
- public LogItem(Parcel in) {
- mArgs = in.readArray(Object.class.getClassLoader());
- mMessage = in.readString();
- mRessourceId = in.readInt();
- mLevel = LogLevel.getEnumByValue(in.readInt());
+ public LogItem(Parcel in) {
+ mArgs = in.readArray(Object.class.getClassLoader());
+ mMessage = in.readString();
+ mRessourceId = in.readInt();
+ mLevel = LogLevel.getEnumByValue(in.readInt());
mVerbosityLevel = in.readInt();
- logtime = in.readLong();
- }
+ logtime = in.readLong();
+ }
- public static final Parcelable.Creator<LogItem> CREATOR
- = new Parcelable.Creator<LogItem>() {
- public LogItem createFromParcel(Parcel in) {
- return new LogItem(in);
- }
+ public static final Parcelable.Creator<LogItem> CREATOR
+ = new Parcelable.Creator<LogItem>() {
+ public LogItem createFromParcel(Parcel in) {
+ return new LogItem(in);
+ }
- public LogItem[] newArray(int size) {
- return new LogItem[size];
- }
- };
+ public LogItem[] newArray(int size) {
+ return new LogItem[size];
+ }
+ };
- public LogItem(LogLevel loglevel,int ressourceId, Object... args) {
+ public LogItem(LogLevel loglevel, int ressourceId, Object... args) {
mRessourceId = ressourceId;
- mArgs =args;
+ mArgs = args;
mLevel = loglevel;
}
- public LogItem(LogLevel loglevel, String msg) {
- mLevel = loglevel;
- mMessage = msg;
- }
+ public LogItem(LogLevel loglevel, String msg) {
+ mLevel = loglevel;
+ mMessage = msg;
+ }
- public LogItem(LogLevel loglevel, int ressourceId) {
- mRessourceId =ressourceId;
- mLevel = loglevel;
- }
+ public LogItem(LogLevel loglevel, int ressourceId) {
+ mRessourceId = ressourceId;
+ mLevel = loglevel;
+ }
- public String getString(Context c) {
+ public String getString(Context c) {
try {
- if(mMessage !=null) {
- return mMessage;
- } else {
- if(c!=null) {
- if(mRessourceId==R.string.mobile_info)
- return getMobileInfoString(c);
- if(mArgs == null)
- return c.getString(mRessourceId);
- else
- return c.getString(mRessourceId,mArgs);
- } else {
- String str = String.format(Locale.ENGLISH,"Log (no context) resid %d", mRessourceId);
- if(mArgs !=null)
- for(Object o:mArgs)
- str += "|" + o.toString();
-
- return str;
- }
- }
+ if (mMessage != null) {
+ return mMessage;
+ } else {
+ if (c != null) {
+ if (mRessourceId == R.string.mobile_info)
+ return getMobileInfoString(c);
+ if (mArgs == null)
+ return c.getString(mRessourceId);
+ else
+ return c.getString(mRessourceId, mArgs);
+ } else {
+ String str = String.format(Locale.ENGLISH, "Log (no context) resid %d", mRessourceId);
+ if (mArgs != null)
+ str += TextUtils.join("|", mArgs);
+
+
+ return str;
+ }
+ }
} catch (UnknownFormatConversionException e) {
if (c != null)
throw new UnknownFormatConversionException(e.getLocalizedMessage() + getString(null));
@@ -235,68 +242,66 @@ public class VpnStatus {
throw e;
} catch (java.util.FormatFlagsConversionMismatchException e) {
if (c != null)
- throw new FormatFlagsConversionMismatchException(e.getLocalizedMessage() + getString(null),e.getConversion());
+ throw new FormatFlagsConversionMismatchException(e.getLocalizedMessage() + getString(null), e.getConversion());
else
throw e;
}
- }
+ }
- public LogLevel getLogLevel()
- {
+ public LogLevel getLogLevel() {
return mLevel;
}
// The lint is wrong here
- @SuppressLint("StringFormatMatches")
- private String getMobileInfoString(Context c) {
- c.getPackageManager();
- String apksign="error getting package signature";
-
- String version="error getting version";
- try {
- Signature raw = c.getPackageManager().getPackageInfo(c.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));
- MessageDigest md = MessageDigest.getInstance("SHA-1");
- byte[] der = cert.getEncoded();
- md.update(der);
- byte[] digest = md.digest();
-
- if (Arrays.equals(digest, officalkey))
- apksign = c.getString(R.string.official_build);
- else if (Arrays.equals(digest, officaldebugkey))
- apksign = c.getString(R.string.debug_build);
- else if (Arrays.equals(digest, amazonkey))
- apksign = "amazon version";
- else if (Arrays.equals(digest, fdroidkey))
+ @SuppressLint("StringFormatMatches")
+ private String getMobileInfoString(Context c) {
+ c.getPackageManager();
+ String apksign = "error getting package signature";
+
+ String version = "error getting version";
+ try {
+ Signature raw = c.getPackageManager().getPackageInfo(c.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] der = cert.getEncoded();
+ md.update(der);
+ byte[] digest = md.digest();
+
+ if (Arrays.equals(digest, officalkey))
+ apksign = c.getString(R.string.official_build);
+ else if (Arrays.equals(digest, officaldebugkey))
+ apksign = c.getString(R.string.debug_build);
+ else if (Arrays.equals(digest, amazonkey))
+ apksign = "amazon version";
+ else if (Arrays.equals(digest, fdroidkey))
apksign = "F-Droid built and signed version";
else
- apksign = c.getString(R.string.built_by,cert.getSubjectX500Principal().getName());
+ apksign = c.getString(R.string.built_by, cert.getSubjectX500Principal().getName());
- PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0);
- version = packageinfo.versionName;
+ PackageInfo packageinfo = c.getPackageManager().getPackageInfo(c.getPackageName(), 0);
+ version = packageinfo.versionName;
- } catch (NameNotFoundException e) {
- } catch (CertificateException e) {
- } catch (NoSuchAlgorithmException e) {
- }
+ } catch (NameNotFoundException | CertificateException |
+ NoSuchAlgorithmException ignored) {
+ }
- Object[] argsext = Arrays.copyOf(mArgs, mArgs.length+2);
- argsext[argsext.length-1]=apksign;
- argsext[argsext.length-2]=version;
+ Object[] argsext = Arrays.copyOf(mArgs, mArgs.length + 2);
+ argsext[argsext.length - 1] = apksign;
+ argsext[argsext.length - 2] = version;
- return c.getString(R.string.mobile_info_extended, argsext);
+ return c.getString(R.string.mobile_info_extended, argsext);
- }
+ }
- public long getLogtime() {
- return logtime;
- }
+ public long getLogtime() {
+ return logtime;
+ }
public int getVerbosityLevel() {
- if (mVerbosityLevel==-1) {
+ if (mVerbosityLevel == -1) {
// Hack:
// For message not from OpenVPN, report the status level as log level
return mLevel.getInt();
@@ -305,90 +310,93 @@ public class VpnStatus {
}
}
+ public void saveLogToDisk(Context c) {
+
+ File logOut = new File(c.getCacheDir(), "log.xml");
+
+ }
+
+ public interface LogListener {
+ void newLog(LogItem logItem);
+ }
+
+ public interface StateListener {
+ void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level);
+ }
+
+ public interface ByteCountListener {
+ void updateByteCount(long in, long out, long diffIn, long diffOut);
+ }
+
+ public synchronized static void logMessage(LogLevel level, String prefix, String message) {
+ newLogItem(new LogItem(level, prefix + message));
+
+ }
+
+ public synchronized static void clearLog() {
+ logbuffer.clear();
+ logInformation();
+ }
+
+ private static void logInformation() {
+ logInfo(R.string.mobile_info, Build.MODEL, Build.BOARD, Build.BRAND, Build.VERSION.SDK_INT);
+ }
+
+ public synchronized static void addLogListener(LogListener ll) {
+ logListener.add(ll);
+ }
+
+ public synchronized static void removeLogListener(LogListener ll) {
+ logListener.remove(ll);
+ }
+
+ public synchronized static void addByteCountListener(ByteCountListener bcl) {
+ bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]);
+ byteCountListener.add(bcl);
+ }
+ public synchronized static void removeByteCountListener(ByteCountListener bcl) {
+ byteCountListener.remove(bcl);
+ }
+
+
+ public synchronized static void addStateListener(StateListener sl) {
+ if (!stateListener.contains(sl)) {
+ stateListener.add(sl);
+ if (mLaststate != null)
+ sl.updateState(mLaststate, mLaststatemsg, mLastStateresid, mLastLevel);
+ }
+ }
- public interface LogListener {
- void newLog(LogItem logItem);
- }
-
- public interface StateListener {
- void updateState(String state, String logmessage, int localizedResId, ConnectionStatus level);
- }
-
- public interface ByteCountListener {
- void updateByteCount(long in, long out, long diffIn, long diffOut);
- }
-
- public synchronized static void logMessage(LogLevel level,String prefix, String message)
- {
- newLogItem(new LogItem(level, prefix + message));
-
- }
-
- public synchronized static void clearLog() {
- logbuffer.clear();
- logInformation();
- }
-
- private static void logInformation() {
- logInfo(R.string.mobile_info,Build.MODEL, Build.BOARD,Build.BRAND,Build.VERSION.SDK_INT);
- }
-
- public synchronized static void addLogListener(LogListener ll){
- logListener.add(ll);
- }
-
- public synchronized static void removeLogListener(LogListener ll) {
- logListener.remove(ll);
- }
-
- public synchronized static void addByteCountListener(ByteCountListener bcl) {
- bcl.updateByteCount(mlastByteCount[0], mlastByteCount[1], mlastByteCount[2], mlastByteCount[3]);
- byteCountListener.add(bcl);
- }
-
- public synchronized static void removeByteCountListener(ByteCountListener bcl) {
- byteCountListener.remove(bcl);
- }
-
-
- public synchronized static void addStateListener(StateListener sl){
- if(!stateListener.contains(sl)){
- stateListener.add(sl);
- if(mLaststate!=null)
- sl.updateState(mLaststate, mLaststatemsg, mLastStateresid, mLastLevel);
- }
- }
-
- private static int getLocalizedState(String state){
- if (state.equals("CONNECTING"))
- return R.string.state_connecting;
- else if (state.equals("WAIT"))
- return R.string.state_wait;
- else if (state.equals("AUTH"))
- return R.string.state_auth;
- else if (state.equals("GET_CONFIG"))
- return R.string.state_get_config;
- else if (state.equals("ASSIGN_IP"))
- return R.string.state_assign_ip;
- else if (state.equals("ADD_ROUTES"))
- return R.string.state_add_routes;
- else if (state.equals("CONNECTED"))
- return R.string.state_connected;
- else if (state.equals("DISCONNECTED"))
- return R.string.state_disconnected;
- else if (state.equals("RECONNECTING"))
- return R.string.state_reconnecting;
- else if (state.equals("EXITING"))
- return R.string.state_exiting;
- else if (state.equals("RESOLVE"))
- return R.string.state_resolve;
- else if (state.equals("TCP_CONNECT"))
- return R.string.state_tcp_connect;
- else
- return R.string.unknown_state;
-
- }
+ private static int getLocalizedState(String state) {
+ if (state.equals("CONNECTING"))
+ return R.string.state_connecting;
+ else if (state.equals("WAIT"))
+ return R.string.state_wait;
+ else if (state.equals("AUTH"))
+ return R.string.state_auth;
+ else if (state.equals("GET_CONFIG"))
+ return R.string.state_get_config;
+ else if (state.equals("ASSIGN_IP"))
+ return R.string.state_assign_ip;
+ else if (state.equals("ADD_ROUTES"))
+ return R.string.state_add_routes;
+ else if (state.equals("CONNECTED"))
+ return R.string.state_connected;
+ else if (state.equals("DISCONNECTED"))
+ return R.string.state_disconnected;
+ else if (state.equals("RECONNECTING"))
+ return R.string.state_reconnecting;
+ else if (state.equals("EXITING"))
+ return R.string.state_exiting;
+ else if (state.equals("RESOLVE"))
+ return R.string.state_resolve;
+ else if (state.equals("TCP_CONNECT"))
+ return R.string.state_tcp_connect;
+ else
+ return R.string.unknown_state;
+
+ }
public static void updateStatePause(OpenVPNManagement.pauseReason pauseReason) {
switch (pauseReason) {
@@ -405,88 +413,84 @@ public class VpnStatus {
}
- private static ConnectionStatus getLevel(String state){
- String[] noreplyet = {"CONNECTING","WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"};
- String[] reply = {"AUTH","GET_CONFIG","ASSIGN_IP","ADD_ROUTES"};
- String[] connected = {"CONNECTED"};
- String[] notconnected = {"DISCONNECTED", "EXITING"};
-
- for(String x:noreplyet)
- if(state.equals(x))
- return ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
-
- for(String x:reply)
- if(state.equals(x))
- return ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED;
+ private static ConnectionStatus getLevel(String state) {
+ String[] noreplyet = {"CONNECTING", "WAIT", "RECONNECTING", "RESOLVE", "TCP_CONNECT"};
+ String[] reply = {"AUTH", "GET_CONFIG", "ASSIGN_IP", "ADD_ROUTES"};
+ String[] connected = {"CONNECTED"};
+ String[] notconnected = {"DISCONNECTED", "EXITING"};
- for(String x:connected)
- if(state.equals(x))
- return ConnectionStatus.LEVEL_CONNECTED;
+ for (String x : noreplyet)
+ if (state.equals(x))
+ return ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
- for(String x:notconnected)
- if(state.equals(x))
- return ConnectionStatus.LEVEL_NOTCONNECTED;
+ for (String x : reply)
+ if (state.equals(x))
+ return ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED;
- return ConnectionStatus.UNKNOWN_LEVEL;
+ for (String x : connected)
+ if (state.equals(x))
+ return ConnectionStatus.LEVEL_CONNECTED;
- }
+ for (String x : notconnected)
+ if (state.equals(x))
+ return ConnectionStatus.LEVEL_NOTCONNECTED;
+ return ConnectionStatus.UNKNOWN_LEVEL;
+ }
- public synchronized static void removeStateListener(StateListener sl) {
- stateListener.remove(sl);
- }
+ public synchronized static void removeStateListener(StateListener sl) {
+ stateListener.remove(sl);
+ }
- synchronized public static LogItem[] getlogbuffer() {
+ synchronized public static LogItem[] getlogbuffer() {
- // The stoned way of java to return an array from a vector
- // brought to you by eclipse auto complete
- return logbuffer.toArray(new LogItem[logbuffer.size()]);
+ // The stoned way of java to return an array from a vector
+ // brought to you by eclipse auto complete
+ return logbuffer.toArray(new LogItem[logbuffer.size()]);
- }
+ }
- public static void updateStateString (String state, String msg) {
- int rid = getLocalizedState(state);
- ConnectionStatus level = getLevel(state);
- updateStateString(state, msg, rid, level);
- }
+ public static void updateStateString(String state, String msg) {
+ int rid = getLocalizedState(state);
+ ConnectionStatus level = getLevel(state);
+ updateStateString(state, msg, rid, level);
+ }
- public synchronized static void updateStateString(String state, String msg, int resid, ConnectionStatus level) {
+ public synchronized static void updateStateString(String state, String msg, int resid, ConnectionStatus level) {
// Workound for OpenVPN doing AUTH and wait and being connected
// Simply ignore these state
if (mLastLevel == ConnectionStatus.LEVEL_CONNECTED &&
- (state.equals("WAIT") || state.equals("AUTH")))
- {
- newLogItem(new LogItem((LogLevel.DEBUG), String.format("Ignoring OpenVPN Status in CONNECTED state (%s->%s): %s",state,level.toString(),msg)));
+ (state.equals("WAIT") || state.equals("AUTH"))) {
+ newLogItem(new LogItem((LogLevel.DEBUG), String.format("Ignoring OpenVPN Status in CONNECTED state (%s->%s): %s", state, level.toString(), msg)));
return;
}
- mLaststate= state;
- mLaststatemsg = msg;
- mLastStateresid = resid;
- mLastLevel = level;
-
+ mLaststate = state;
+ mLaststatemsg = msg;
+ mLastStateresid = resid;
+ mLastLevel = level;
for (StateListener sl : stateListener) {
- sl.updateState(state,msg,resid,level);
- }
+ sl.updateState(state, msg, resid, level);
+ }
//newLogItem(new LogItem((LogLevel.DEBUG), String.format("New OpenVPN Status (%s->%s): %s",state,level.toString(),msg)));
- }
+ }
- public static void logInfo(String message) {
- newLogItem(new LogItem(LogLevel.INFO, message));
- }
+ public static void logInfo(String message) {
+ newLogItem(new LogItem(LogLevel.INFO, message));
+ }
public static void logDebug(String message) {
newLogItem(new LogItem(LogLevel.DEBUG, message));
}
public static void logInfo(int resourceId, Object... args) {
- newLogItem(new LogItem(LogLevel.INFO, resourceId, args));
- }
+ newLogItem(new LogItem(LogLevel.INFO, resourceId, args));
+ }
public static void logDebug(int resourceId, Object... args) {
newLogItem(new LogItem(LogLevel.DEBUG, resourceId, args));
@@ -494,19 +498,19 @@ public class VpnStatus {
private synchronized static void newLogItem(LogItem logItem) {
- logbuffer.addLast(logItem);
- if(logbuffer.size()>MAXLOGENTRIES)
- logbuffer.removeFirst();
+ logbuffer.addLast(logItem);
+ if (logbuffer.size() > MAXLOGENTRIES)
+ logbuffer.removeFirst();
- for (LogListener ll : logListener) {
- ll.newLog(logItem);
- }
- }
+ for (LogListener ll : logListener) {
+ ll.newLog(logItem);
+ }
+ }
- public static void logError(String msg) {
- newLogItem(new LogItem(LogLevel.ERROR, msg));
+ public static void logError(String msg) {
+ newLogItem(new LogItem(LogLevel.ERROR, msg));
- }
+ }
public static void logWarning(int resourceId, Object... args) {
newLogItem(new LogItem(LogLevel.WARNING, resourceId, args));
@@ -518,11 +522,12 @@ public class VpnStatus {
public static void logError(int resourceId) {
- newLogItem(new LogItem(LogLevel.ERROR, resourceId));
- }
- public static void logError(int resourceId, Object... args) {
- newLogItem(new LogItem(LogLevel.ERROR, resourceId, args));
- }
+ newLogItem(new LogItem(LogLevel.ERROR, resourceId));
+ }
+
+ public static void logError(int resourceId, Object... args) {
+ newLogItem(new LogItem(LogLevel.ERROR, resourceId, args));
+ }
public static void logMessageOpenVPN(LogLevel level, int ovpnlevel, String message) {
newLogItem(new LogItem(level, ovpnlevel, message));
@@ -531,19 +536,17 @@ public class VpnStatus {
public static synchronized void updateByteCount(long in, long out) {
- long lastIn = mlastByteCount[0];
- long lastOut = mlastByteCount[1];
- long diffIn = mlastByteCount[2] = in - lastIn;
- long diffOut = mlastByteCount[3] = out - lastOut;
-
-
-
- mlastByteCount = new long[] {in,out,diffIn,diffOut};
- for(ByteCountListener bcl:byteCountListener){
- bcl.updateByteCount(in, out, diffIn,diffOut);
- }
- }
+ long lastIn = mlastByteCount[0];
+ long lastOut = mlastByteCount[1];
+ long diffIn = mlastByteCount[2] = in - lastIn;
+ long diffOut = mlastByteCount[3] = out - lastOut;
+
+ mlastByteCount = new long[]{in, out, diffIn, diffOut};
+ for (ByteCountListener bcl : byteCountListener) {
+ bcl.updateByteCount(in, out, diffIn, diffOut);
+ }
+ }
}
diff --git a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
index 92bf9ad3..2a75c15e 100644
--- a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
+++ b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
@@ -5,8 +5,6 @@
package de.blinkt.openvpn.fragments;
-import se.leap.bitmaskclient.R;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
diff --git a/app/src/main/java/org/spongycastle/util/encoders/Base64.java b/app/src/main/java/org/spongycastle/util/encoders/Base64.java
index 87bd80a0..0993e7be 100644
--- a/app/src/main/java/org/spongycastle/util/encoders/Base64.java
+++ b/app/src/main/java/org/spongycastle/util/encoders/Base64.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.encoders;
import java.io.ByteArrayOutputStream;
diff --git a/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java b/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java
index 84060707..4248bb8b 100644
--- a/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java
+++ b/app/src/main/java/org/spongycastle/util/encoders/Base64Encoder.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.encoders;
import java.io.IOException;
diff --git a/app/src/main/java/org/spongycastle/util/encoders/Encoder.java b/app/src/main/java/org/spongycastle/util/encoders/Encoder.java
index 106c36b7..2007ac3e 100644
--- a/app/src/main/java/org/spongycastle/util/encoders/Encoder.java
+++ b/app/src/main/java/org/spongycastle/util/encoders/Encoder.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.encoders;
import java.io.IOException;
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java b/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java
index 0127ca0c..b9474ed3 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemGenerationException.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
import java.io.IOException;
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java b/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java
index 4adb815e..6d655c87 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemHeader.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
public class PemHeader
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java b/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java
index 6f7c79c5..59186e09 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemObject.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
import java.util.ArrayList;
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java b/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java
index 1a8cea6d..ddce091c 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemObjectGenerator.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
public interface PemObjectGenerator
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java b/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java
index cbbebab9..0b3b55c4 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemReader.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
import java.io.BufferedReader;
@@ -49,7 +54,7 @@ public class PemReader
{
String line;
String endMarker = END + type;
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
List headers = new ArrayList();
while ((line = readLine()) != null)
diff --git a/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java b/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java
index f5a6a363..25730efd 100644
--- a/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java
+++ b/app/src/main/java/org/spongycastle/util/io/pem/PemWriter.java
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2012-2014 Arne Schwabe
+ * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ */
+
package org.spongycastle.util.io.pem;
import java.io.BufferedWriter;
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index ee64a1b3..bdc36e89 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -29,11 +29,10 @@ import org.jetbrains.annotations.*;
import org.json.*;
import java.net.*;
-import java.util.*;
import butterknife.*;
-import de.blinkt.openvpn.activities.*;
import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.*;
/**
* The main user facing Activity of Bitmask Android, consisting of status, controls,
@@ -42,7 +41,7 @@ import se.leap.bitmaskclient.eip.*;
* @author Sean Leonard <meanderingcode@aetherislands.net>
* @author parmegv
*/
-public class Dashboard extends Activity implements SessionDialog.SessionDialogInterface, ProviderAPIResultReceiver.Receiver, Observer {
+public class Dashboard extends Activity implements ProviderAPIResultReceiver.Receiver {
protected static final int CONFIGURE_LEAP = 0;
protected static final int SWITCH_PROVIDER = 1;
@@ -62,14 +61,10 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
@InjectView(R.id.providerName)
TextView provider_name;
- @InjectView(R.id.user_session_status)
- TextView user_session_status_text_view;
- @InjectView(R.id.user_session_status_progress)
- ProgressBar user_session_status_progress_bar;
-
- EipFragment eip_fragment;
- private Provider provider;
- private UserSessionStatus user_session_status;
+
+ VpnFragment eip_fragment;
+ UserStatusFragment user_status_fragment;
+ private static Provider provider = new Provider();
public ProviderAPIResultReceiver providerAPI_result_receiver;
private boolean switching_provider;
@@ -78,21 +73,23 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
super.onCreate(savedInstanceState);
app = this;
- user_session_status = UserSessionStatus.getInstance();
- user_session_status.addObserver(this);
PRNGFixes.apply();
preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
fragment_manager = new FragmentManagerEnhanced(getFragmentManager());
handleVersion();
+ User.init(getString(R.string.default_username));
+
+ ProviderAPICommand.initialize(this);
+ providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
restoreProvider(savedInstanceState);
- if (provider == null || provider.getName().isEmpty())
+ if (!provider.isConfigured())
startActivityForResult(new Intent(this, ConfigurationWizard.class), CONFIGURE_LEAP);
else {
buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
- restoreSessionStatus(savedInstanceState);
+ user_status_fragment.restoreSessionStatus(savedInstanceState);
}
}
@@ -101,32 +98,20 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
if (savedInstanceState.containsKey(Provider.KEY))
provider = savedInstanceState.getParcelable(Provider.KEY);
}
- if (provider == null && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false))
+ if (!provider.isConfigured() && preferences.getBoolean(Constants.PROVIDER_CONFIGURED, false))
provider = getSavedProviderFromSharedPreferences();
}
- private void restoreSessionStatus(Bundle savedInstanceState) {
- if (savedInstanceState != null)
- if (savedInstanceState.containsKey(UserSessionStatus.TAG)) {
- UserSessionStatus.SessionStatus status = (UserSessionStatus.SessionStatus) savedInstanceState.getSerializable(UserSessionStatus.TAG);
- user_session_status.updateStatus(status);
- }
- }
-
@Override
protected void onSaveInstanceState(@NotNull Bundle outState) {
- if (provider != null)
- outState.putParcelable(Provider.KEY, provider);
- if (user_session_status_text_view != null && user_session_status_text_view.getVisibility() == TextView.VISIBLE)
- outState.putSerializable(UserSessionStatus.TAG, user_session_status.sessionStatus());
-
+ outState.putParcelable(Provider.KEY, provider);
super.onSaveInstanceState(outState);
}
private Provider getSavedProviderFromSharedPreferences() {
- Provider provider = null;
+ Provider provider = new Provider();
try {
- provider = new Provider(new URL(preferences.getString(Provider.MAIN_URL, "")));
+ provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, "")));
provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));
} catch (MalformedURLException | JSONException e) {
e.printStackTrace();
@@ -161,12 +146,12 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
providerToPreferences(provider);
buildDashboard(false);
- invalidateOptionsMenu();
+ invalidateOptionsMenuOnUiThread();
if (data.hasExtra(SessionDialog.TAG)) {
sessionDialog(Bundle.EMPTY);
}
- } else if (resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) {
+ } else if (resultCode == RESULT_CANCELED && data != null && data.hasExtra(ACTION_QUIT)) {
finish();
} else
configErrorDialog();
@@ -213,33 +198,35 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
ButterKnife.inject(this);
provider_name.setText(provider.getDomain());
+
+ user_status_fragment = new UserStatusFragment();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(Provider.ALLOW_REGISTRATION, provider.allowsRegistration());
+ user_status_fragment.setArguments(bundle);
+ fragment_manager.replace(R.id.user_status_fragment, user_status_fragment, UserStatusFragment.TAG);
+
if (provider.hasEIP()) {
- fragment_manager.removePreviousFragment(EipFragment.TAG);
- eip_fragment = new EipFragment();
+ fragment_manager.removePreviousFragment(VpnFragment.TAG);
+ eip_fragment = new VpnFragment();
if (hide_and_turn_on_eip) {
preferences.edit().remove(Dashboard.START_ON_BOOT).apply();
Bundle arguments = new Bundle();
- arguments.putBoolean(EipFragment.START_ON_BOOT, true);
+ arguments.putBoolean(VpnFragment.START_ON_BOOT, true);
if (eip_fragment != null) eip_fragment.setArguments(arguments);
}
- fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG);
+ fragment_manager.replace(R.id.servicesCollection, eip_fragment, VpnFragment.TAG);
if (hide_and_turn_on_eip) {
onBackPressed();
}
}
- handleNewUserSessionStatus(user_session_status);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (provider.allowsRegistration()) {
menu.findItem(R.id.signup_button).setVisible(true);
-
- boolean logged_in = User.loggedIn();
- menu.findItem(R.id.login_button).setVisible(!logged_in);
- menu.findItem(R.id.logout_button).setVisible(logged_in);
}
return true;
}
@@ -261,15 +248,9 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
return true;
case R.id.switch_provider:
switching_provider = true;
- if (LeapSRPSession.loggedIn()) logOut();
+ if (User.loggedIn()) user_status_fragment.logOut();
else switchProvider();
return true;
- case R.id.login_button:
- sessionDialog(Bundle.EMPTY);
- return true;
- case R.id.logout_button:
- logOut();
- return true;
case R.id.signup_button:
sessionDialog(Bundle.EMPTY);
return true;
@@ -284,131 +265,22 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
}
public void showLog() {
- Intent startLW = new Intent(getContext(), LogWindow.class);
- startActivity(startLW);
- }
-
- @Override
- public void signUp(String username, String password) {
- User.setUserName(username);
- Bundle parameters = bundlePassword(password);
- providerApiCommand(parameters, 0, ProviderAPI.SIGN_UP);
- }
-
- @Override
- public void logIn(String username, String password) {
- User.setUserName(username);
- Bundle parameters = bundlePassword(password);
- providerApiCommand(parameters, 0, ProviderAPI.LOG_IN);
- }
-
- public void logOut() {
- providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.LOG_OUT);
- }
-
- @Override
- public void update(Observable observable, Object data) {
- if (observable instanceof UserSessionStatus) {
- UserSessionStatus status = (UserSessionStatus) observable;
- handleNewUserSessionStatus(status);
- }
- }
-
- private void handleNewUserSessionStatus(UserSessionStatus status) {
- user_session_status = status;
- if (provider.allowsRegistration()) {
- if (user_session_status.inProgress())
- showUserSessionProgressBar();
- else
- hideUserSessionProgressBar();
- changeSessionStatusMessage(user_session_status.toString());
- invalidateOptionsMenu();
- }
- }
-
- private void changeSessionStatusMessage(final String message) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- user_session_status_text_view.setText(message);
- }
- });
- }
-
- private void showUserSessionProgressBar() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- user_session_status_progress_bar.setVisibility(ProgressBar.VISIBLE);
- }
- });
- }
-
- private void hideUserSessionProgressBar() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- user_session_status_progress_bar.setVisibility(ProgressBar.GONE);
- }
- });
+ LogWindowWrapper log_window_wrapper = LogWindowWrapper.getInstance(getContext());
+ log_window_wrapper.showLog();
}
- protected void downloadVpnCertificate() {
- boolean is_authenticated = LeapSRPSession.loggedIn();
+ public void downloadVpnCertificate() {
+ boolean is_authenticated = User.loggedIn();
boolean allowed_anon = preferences.getBoolean(Constants.ALLOWED_ANON, false);
if (allowed_anon || is_authenticated)
- providerApiCommand(Bundle.EMPTY, R.string.downloading_certificate_message, ProviderAPI.DOWNLOAD_CERTIFICATE);
+ ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_CERTIFICATE, providerAPI_result_receiver);
else
sessionDialog(Bundle.EMPTY);
-
- }
-
- private Bundle bundlePassword(String password) {
- Bundle parameters = new Bundle();
- if (!password.isEmpty())
- parameters.putString(SessionDialog.PASSWORD, password);
- return parameters;
- }
-
- protected void providerApiCommand(Bundle parameters, int progressbar_message_resId, String providerApi_action) {
- if (eip_fragment != null && progressbar_message_resId != 0) {
- eip_fragment.progress_bar.setVisibility(ProgressBar.VISIBLE);
- setStatusMessage(progressbar_message_resId);
- }
-
- Intent command = prepareProviderAPICommand(parameters, providerApi_action);
- startService(command);
- }
-
- private Intent prepareProviderAPICommand(Bundle parameters, String action) {
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
-
- Intent command = new Intent(this, ProviderAPI.class);
-
- command.putExtra(ProviderAPI.PARAMETERS, parameters);
- command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver);
- command.setAction(action);
- return command;
- }
-
- public void cancelLoginOrSignup() {
- EipStatus.getInstance().setConnectedOrDisconnected();
}
public void sessionDialog(Bundle resultData) {
-
FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG);
-
- DialogFragment newFragment = new SessionDialog();
- if (provider.getName().equalsIgnoreCase("riseup")) {
- resultData = resultData == Bundle.EMPTY ? new Bundle() : resultData;
- resultData.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true);
- }
- if (resultData != null && !resultData.isEmpty()) {
- newFragment.setArguments(resultData);
- }
- newFragment.show(transaction, SessionDialog.TAG);
+ SessionDialog.getInstance(provider, resultData).show(transaction, SessionDialog.TAG);
}
private void switchProvider() {
@@ -424,7 +296,7 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
if (resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) {
String username = resultData.getString(SessionDialog.USERNAME);
String password = resultData.getString(SessionDialog.PASSWORD);
- logIn(username, password);
+ user_status_fragment.logIn(username, password);
} else if (resultCode == ProviderAPI.FAILED_SIGNUP) {
sessionDialog(resultData);
} else if (resultCode == ProviderAPI.SUCCESSFUL_LOGIN) {
@@ -437,7 +309,6 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
setResult(RESULT_CANCELED);
} else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
eip_fragment.updateEipService();
- eip_fragment.handleNewVpnCertificate();
setResult(RESULT_OK);
} else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
setResult(RESULT_CANCELED);
@@ -449,18 +320,24 @@ public class Dashboard extends Activity implements SessionDialog.SessionDialogIn
}
}
- private void setStatusMessage(int string_resId) {
- if (eip_fragment != null && eip_fragment.status_message != null)
- eip_fragment.status_message.setText(string_resId);
- }
-
public static Context getContext() {
return app;
}
+ public static Provider getProvider() { return provider; }
+
@Override
public void startActivityForResult(Intent intent, int requestCode) {
intent.putExtra(Dashboard.REQUEST_CODE, requestCode);
super.startActivityForResult(intent, requestCode);
}
+
+ public void invalidateOptionsMenuOnUiThread() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ invalidateOptionsMenu();
+ }
+ });
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
new file mode 100644
index 00000000..8daa7d8c
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java
@@ -0,0 +1,37 @@
+package se.leap.bitmaskclient;
+
+import java.net.*;
+
+public class DefaultedURL {
+ private URL DEFAULT_URL;
+ private String default_url = "https://example.net";
+
+ private URL url;
+
+ public DefaultedURL() {
+ try {
+ DEFAULT_URL = new URL(default_url);
+ url = DEFAULT_URL;
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean isDefault() { return url.equals(DEFAULT_URL); }
+
+ public void setUrl(URL url) {
+ this.url = url;
+ }
+
+ public String getDomain() {
+ return url.getHost();
+ }
+
+ public URL getUrl() {
+ return url;
+ }
+
+ public String toString() {
+ return url.toString();
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
index b961350e..49cf3774 100644
--- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
+++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java
@@ -42,7 +42,6 @@ public class LeapSRPSession {
final public static String AUTHORIZATION_HEADER = "Authorization";
final public static String TAG = "Leap SRP session class tag";
- private User user;
private SRPParameters params;
private String username;
private String password;
@@ -338,7 +337,7 @@ public class LeapSRPSession {
return token;
}
- protected static boolean loggedIn() {
+ public static boolean loggedIn() {
return !token.isEmpty();
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java
new file mode 100644
index 00000000..2476f6a4
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/LogWindowWrapper.java
@@ -0,0 +1,28 @@
+package se.leap.bitmaskclient;
+
+import android.content.*;
+
+import de.blinkt.openvpn.activities.*;
+
+public class LogWindowWrapper {
+ private static LogWindowWrapper instance;
+
+ private static String TAG = LogWindowWrapper.class.getName();
+ private Context context;
+
+ public LogWindowWrapper(Context context) {
+ this.context = context;
+ }
+
+ public void showLog() {
+ Intent startLW = new Intent(context, LogWindow.class);
+ startLW.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(startLW);
+ }
+
+ public static LogWindowWrapper getInstance(Context context) {
+ if(instance == null)
+ instance = new LogWindowWrapper(context);
+ return instance;
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index ee06a586..559b47d1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -30,8 +30,9 @@ import java.util.*;
*/
public final class Provider implements Parcelable {
- private JSONObject definition; // Represents our Provider's provider.json
- private URL main_url;
+ private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json
+ private DefaultedURL main_url = new DefaultedURL();
+ private String certificate_pin = "";
final public static String
API_URL = "api_uri",
@@ -58,12 +59,15 @@ public final class Provider implements Parcelable {
private static final String API_TERM_DEFAULT_LANGUAGE = "default_language";
protected static final String[] API_EIP_TYPES = {"openvpn"};
+ public Provider() { }
+
public Provider(URL main_url) {
- this.main_url = main_url;
+ this.main_url.setUrl(main_url);
}
- public Provider(File provider_file) {
-
+ public Provider(URL main_url, String certificate_pin) {
+ this.main_url.setUrl(main_url);
+ this.certificate_pin = certificate_pin;
}
public static final Parcelable.Creator<Provider> CREATOR
@@ -79,17 +83,23 @@ public final class Provider implements Parcelable {
private Provider(Parcel in) {
try {
- main_url = new URL(in.readString());
+ main_url.setUrl(new URL(in.readString()));
String definition_string = in.readString();
- if (definition_string != null)
+ if (!definition_string.isEmpty())
definition = new JSONObject((definition_string));
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (JSONException e) {
+ } catch (MalformedURLException | JSONException e) {
e.printStackTrace();
}
}
+ public boolean isConfigured() {
+ return !main_url.isDefault() && definition.length() > 0;
+ }
+
+ protected void setUrl(URL url) {
+ main_url.setUrl(url);
+ }
+
protected void define(JSONObject provider_json) {
definition = provider_json;
}
@@ -99,14 +109,16 @@ public final class Provider implements Parcelable {
}
protected String getDomain() {
- return main_url.getHost();
+ return main_url.getDomain();
}
- protected URL mainUrl() {
+ protected DefaultedURL mainUrl() {
return main_url;
}
- protected String getName() {
+ protected String certificatePin() { return certificate_pin; }
+
+ public String getName() {
// Should we pass the locale in, or query the system here?
String lang = Locale.getDefault().getLanguage();
String name = "";
@@ -116,7 +128,7 @@ public final class Provider implements Parcelable {
else throw new JSONException("Provider not defined");
} catch (JSONException e) {
if (main_url != null) {
- String host = main_url.getHost();
+ String host = main_url.getDomain();
name = host.substring(0, host.indexOf("."));
}
}
@@ -179,7 +191,8 @@ public final class Provider implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int i) {
- parcel.writeString(main_url.toString());
+ if(main_url != null)
+ parcel.writeString(main_url.toString());
if (definition != null)
parcel.writeString(definition.toString());
}
@@ -188,7 +201,7 @@ public final class Provider implements Parcelable {
public boolean equals(Object o) {
if (o instanceof Provider) {
Provider p = (Provider) o;
- return p.mainUrl().getHost().equals(mainUrl().getHost());
+ return p.mainUrl().getDomain().equals(mainUrl().getDomain());
} else return false;
}
@@ -204,6 +217,6 @@ public final class Provider implements Parcelable {
@Override
public int hashCode() {
- return mainUrl().getHost().hashCode();
+ return mainUrl().getDomain().hashCode();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
new file mode 100644
index 00000000..0e4cfe8a
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java
@@ -0,0 +1,45 @@
+package se.leap.bitmaskclient;
+
+import android.content.*;
+import android.os.*;
+
+import org.jetbrains.annotations.*;
+
+public class ProviderAPICommand {
+ private static Context context;
+
+ private static String action;
+ private static Bundle parameters;
+ private static ResultReceiver result_receiver;
+
+ public static void initialize(Context context) {
+ ProviderAPICommand.context = context;
+ }
+
+ private static boolean isInitialized() {
+ return context != null;
+ }
+
+ public static void execute(Bundle parameters, @NotNull String action, @NotNull ResultReceiver result_receiver) throws IllegalStateException {
+ if(!isInitialized()) throw new IllegalStateException();
+
+ ProviderAPICommand.action = action;
+ ProviderAPICommand.parameters = parameters;
+ ProviderAPICommand.result_receiver = result_receiver;
+
+ Intent intent = setUpIntent();
+ context.startService(intent);
+ }
+
+ private static Intent setUpIntent() {
+ Intent command = new Intent(context, ProviderAPI.class);
+
+ command.setAction(action);
+ command.putExtra(ProviderAPI.PARAMETERS, parameters);
+ command.putExtra(ProviderAPI.RECEIVER_KEY, result_receiver);
+
+ return command;
+ }
+
+
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
index 533e5caf..9b880f89 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java
@@ -26,8 +26,9 @@ import android.os.*;
public class ProviderAPIResultReceiver extends ResultReceiver {
private Receiver mReceiver;
- public ProviderAPIResultReceiver(Handler handler) {
+ public ProviderAPIResultReceiver(Handler handler, Receiver receiver) {
super(handler);
+ setReceiver(receiver);
// TODO Auto-generated constructor stub
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
index 40fe8b5a..13ef9b80 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
@@ -28,7 +28,8 @@ public class ProviderManager implements AdapteeCollection<Provider> {
if (instance == null)
instance = new ProviderManager(assets_manager);
- instance.addCustomProviders(external_files_dir);
+ if(external_files_dir != null)
+ instance.addCustomProviders(external_files_dir);
return instance;
}
@@ -49,11 +50,14 @@ public class ProviderManager implements AdapteeCollection<Provider> {
Set<Provider> providers = new HashSet<Provider>();
try {
for (String file : relative_file_paths) {
- String main_url = extractMainUrlFromInputStream(assets_manager.open(directory + "/" + file));
- providers.add(new Provider(new URL(main_url)));
+ InputStream provider_file = assets_manager.open(directory + "/" + file);
+ String main_url = extractMainUrlFromInputStream(provider_file);
+ String certificate_pin = extractCertificatePinFromInputStream(provider_file);
+ if(certificate_pin.isEmpty())
+ providers.add(new Provider(new URL(main_url)));
+ else
+ providers.add(new Provider(new URL(main_url), certificate_pin));
}
- } catch (MalformedURLException e) {
- e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
@@ -75,36 +79,50 @@ public class ProviderManager implements AdapteeCollection<Provider> {
String main_url = extractMainUrlFromInputStream(new FileInputStream(external_files_dir.getAbsolutePath() + "/" + file));
providers.add(new Provider(new URL(main_url)));
}
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (FileNotFoundException e) {
+ } catch (MalformedURLException | FileNotFoundException e) {
e.printStackTrace();
}
return providers;
}
- private String extractMainUrlFromInputStream(InputStream input_stream_file_contents) {
+ private String extractMainUrlFromInputStream(InputStream input_stream) {
String main_url = "";
- byte[] bytes = new byte[0];
+
+ JSONObject file_contents = inputStreamToJson(input_stream);
+ if(file_contents != null)
+ main_url = file_contents.optString(Provider.MAIN_URL);
+ return main_url;
+ }
+
+ private String extractCertificatePinFromInputStream(InputStream input_stream) {
+ String certificate_pin = "";
+
+ JSONObject file_contents = inputStreamToJson(input_stream);
+ if(file_contents != null)
+ certificate_pin = file_contents.optString(Provider.CA_CERT_FINGERPRINT);
+
+ return certificate_pin;
+ }
+
+ private JSONObject inputStreamToJson(InputStream input_stream) {
+ JSONObject json = null;
try {
- bytes = new byte[input_stream_file_contents.available()];
- if (input_stream_file_contents.read(bytes) > 0) {
- JSONObject file_contents = new JSONObject(new String(bytes));
- main_url = file_contents.getString(Provider.MAIN_URL);
- }
- } catch (IOException e) {
- e.printStackTrace();
- } catch (JSONException e) {
+ byte[] bytes = new byte[input_stream.available()];
+ if (input_stream.read(bytes) > 0)
+ json = new JSONObject(new String(bytes));
+ input_stream.reset();
+ } catch (IOException | JSONException e) {
e.printStackTrace();
}
- return main_url;
+ return json;
}
public Set<Provider> providers() {
Set<Provider> all_providers = new HashSet<Provider>();
all_providers.addAll(default_providers);
- all_providers.addAll(custom_providers);
+ if(custom_providers != null)
+ all_providers.addAll(custom_providers);
return all_providers;
}
@@ -124,25 +142,27 @@ public class ProviderManager implements AdapteeCollection<Provider> {
}
@Override
- public void add(Provider element) {
+ public boolean add(Provider element) {
if (!default_providers.contains(element))
- custom_providers.add(element);
+ return custom_providers.add(element);
+ else return true;
}
@Override
- public void remove(Provider element) {
- custom_providers.remove(element);
+ public boolean remove(Object element) {
+ return custom_providers.remove(element);
}
@Override
- public void addAll(Collection<Provider> elements) {
- custom_providers.addAll(elements);
+ public boolean addAll(Collection<? extends Provider> elements) {
+ return custom_providers.addAll(elements);
}
@Override
- public void removeAll(Collection<Provider> elements) {
- custom_providers.removeAll(elements);
- default_providers.removeAll(elements);
+ public boolean removeAll(Collection<?> elements) {
+ if(!elements.getClass().equals(Provider.class))
+ return false;
+ return default_providers.removeAll(elements) || custom_providers.removeAll(elements);
}
@Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java b/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java
deleted file mode 100644
index e43c8a25..00000000
--- a/app/src/main/java/se/leap/bitmaskclient/UserSessionStatus.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package se.leap.bitmaskclient;
-
-import android.os.*;
-
-import java.util.*;
-
-public class UserSessionStatus extends Observable {
- public static String TAG = UserSessionStatus.class.getSimpleName();
- private static UserSessionStatus current_status;
-
- public enum SessionStatus {
- LOGGED_IN,
- LOGGED_OUT,
- NOT_LOGGED_IN,
- DIDNT_LOG_OUT,
- LOGGING_IN,
- LOGGING_OUT,
- SIGNING_UP
- }
-
- private static SessionStatus session_status = SessionStatus.NOT_LOGGED_IN;
-
- public static UserSessionStatus getInstance() {
- if (current_status == null) {
- current_status = new UserSessionStatus();
- }
- return current_status;
- }
-
- private UserSessionStatus() {
- }
-
- private void sessionStatus(SessionStatus session_status) {
- this.session_status = session_status;
- }
-
- public SessionStatus sessionStatus() {
- return session_status;
- }
-
- public boolean inProgress() {
- return session_status == SessionStatus.LOGGING_IN
- || session_status == SessionStatus.LOGGING_OUT;
- }
-
- public static void updateStatus(SessionStatus session_status) {
- current_status = getInstance();
- current_status.sessionStatus(session_status);
- current_status.setChanged();
- current_status.notifyObservers();
- }
-
- @Override
- public String toString() {
- String username = User.userName();
-
- return username + " " + conjugateToBe(username) + " "
- + session_status.toString().toLowerCase().replaceAll("_", " ");
- }
-
- private String conjugateToBe(String subject) {
- String conjugation = "";
- if(subject.equalsIgnoreCase("I"))
- conjugation = "am";
- else if(subject.equalsIgnoreCase("you") || subject.equalsIgnoreCase("we")|| subject.equalsIgnoreCase("they"))
- conjugation = "are";
- else conjugation = "is";
-
- return conjugation;
- }
-}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
index 02eedd77..2e3d7524 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/VpnFragment.java
@@ -19,7 +19,6 @@ package se.leap.bitmaskclient;
import android.app.*;
import android.content.*;
import android.os.*;
-import android.util.*;
import android.view.*;
import android.widget.*;
@@ -29,35 +28,35 @@ import java.util.*;
import butterknife.*;
import de.blinkt.openvpn.activities.*;
+import mbanje.kurt.fabbutton.*;
import se.leap.bitmaskclient.eip.*;
-public class EipFragment extends Fragment implements Observer {
+public class VpnFragment extends Fragment implements Observer {
- public static String TAG = EipFragment.class.getSimpleName();
+ public static String TAG = VpnFragment.class.getSimpleName();
- protected static final String IS_PENDING = TAG + ".is_pending";
+ public static final String IS_PENDING = TAG + ".is_pending";
protected static final String IS_CONNECTED = TAG + ".is_connected";
- protected static final String STATUS_MESSAGE = TAG + ".status_message";
public static final String START_ON_BOOT = "start on boot";
- @InjectView(R.id.eipSwitch)
- Switch eip_switch;
- @InjectView(R.id.status_message)
- TextView status_message;
- @InjectView(R.id.eipProgress)
- ProgressBar progress_bar;
+ @InjectView(R.id.vpn_Status_Image)
+ FabButton vpn_status_image;
+ @InjectView(R.id.vpn_main_button)
+ Button main_button;
private static Dashboard dashboard;
- private static EIPReceiver mEIPReceiver;
+ private static EIPReceiver eip_receiver;
private static EipStatus eip_status;
- private boolean is_starting_to_connect;
private boolean wants_to_connect;
public void onAttach(Activity activity) {
super.onAttach(activity);
dashboard = (Dashboard) activity;
- dashboard.providerApiCommand(Bundle.EMPTY, 0, ProviderAPI.DOWNLOAD_EIP_SERVICE);
+ ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
+
+ if(eip_receiver != null)
+ ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver);
}
@Override
@@ -65,7 +64,7 @@ public class EipFragment extends Fragment implements Observer {
super.onCreate(savedInstanceState);
eip_status = EipStatus.getInstance();
eip_status.addObserver(this);
- mEIPReceiver = new EIPReceiver(new Handler());
+ eip_receiver = new EIPReceiver(new Handler());
}
@Override
@@ -73,9 +72,6 @@ public class EipFragment extends Fragment implements Observer {
View view = inflater.inflate(R.layout.eip_service_fragment, container, false);
ButterKnife.inject(this, view);
- if (eip_status.isConnecting())
- eip_switch.setVisibility(View.VISIBLE);
-
Bundle arguments = getArguments();
if (arguments != null && arguments.containsKey(START_ON_BOOT) && arguments.getBoolean(START_ON_BOOT))
startEipFromScratch();
@@ -89,8 +85,6 @@ public class EipFragment extends Fragment implements Observer {
eip_status.setConnecting();
else if (savedInstanceState.getBoolean(IS_CONNECTED))
eip_status.setConnectedOrDisconnected();
- else
- status_message.setText(savedInstanceState.getString(STATUS_MESSAGE));
}
@Override
@@ -104,25 +98,20 @@ public class EipFragment extends Fragment implements Observer {
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(IS_PENDING, eip_status.isConnecting());
outState.putBoolean(IS_CONNECTED, eip_status.isConnected());
- outState.putString(STATUS_MESSAGE, status_message.getText().toString());
super.onSaveInstanceState(outState);
}
protected void saveStatus() {
- boolean is_on = eip_switch.isChecked();
+ boolean is_on = eip_status.isConnected() || eip_status.isConnecting();
Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, is_on).commit();
}
- void handleNewVpnCertificate() {
- handleSwitch(!eip_switch.isEnabled());
- }
-
- @OnCheckedChanged(R.id.eipSwitch)
- void handleSwitch(boolean isChecked) {
- if (isChecked)
- handleSwitchOn();
- else
+ @OnClick(R.id.vpn_main_button)
+ void handleIcon() {
+ if (eip_status.isConnected() || eip_status.isConnecting())
handleSwitchOff();
+ else
+ handleSwitchOn();
saveStatus();
}
@@ -156,23 +145,22 @@ public class EipFragment extends Fragment implements Observer {
} else if (eip_status.isConnected()) {
askToStopEIP();
} else
- setDisconnectedUI();
+ updateIcon();
}
private void askPendingStartCancellation() {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard);
alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title))
.setMessage(dashboard.getString(R.string.eip_cancel_connect_text))
- .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() {
+ .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
askToStopEIP();
}
})
- .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() {
+ .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- eip_switch.setChecked(true);
}
})
.show();
@@ -180,15 +168,8 @@ public class EipFragment extends Fragment implements Observer {
public void startEipFromScratch() {
wants_to_connect = false;
- is_starting_to_connect = true;
- progress_bar.setVisibility(View.VISIBLE);
- eip_switch.setVisibility(View.VISIBLE);
- String status = dashboard.getString(R.string.eip_status_start_pending);
- status_message.setText(status);
-
- if (!eip_switch.isChecked()) {
- eip_switch.setChecked(true);
- }
+ eip_status.setConnecting();
+
saveStatus();
eipCommand(Constants.ACTION_START_EIP);
}
@@ -206,12 +187,6 @@ public class EipFragment extends Fragment implements Observer {
}
protected void stopEipIfPossible() {
-
- hideProgressBar();
-
- String message = dashboard.getString(R.string.eip_state_not_connected);
- status_message.setText(message);
-
eipCommand(Constants.ACTION_STOP_EIP);
}
@@ -219,16 +194,15 @@ public class EipFragment extends Fragment implements Observer {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(dashboard);
alertBuilder.setTitle(dashboard.getString(R.string.eip_cancel_connect_title))
.setMessage(dashboard.getString(R.string.eip_warning_browser_inconsistency))
- .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() {
+ .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
stopEipIfPossible();
}
})
- .setNegativeButton(dashboard.getString(R.string.no), new DialogInterface.OnClickListener() {
+ .setNegativeButton(dashboard.getString(android.R.string.no), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- eip_switch.setChecked(true);
}
})
.show();
@@ -248,7 +222,7 @@ public class EipFragment extends Fragment implements Observer {
// TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
Intent vpn_intent = new Intent(dashboard.getApplicationContext(), EIP.class);
vpn_intent.setAction(action);
- vpn_intent.putExtra(Constants.RECEIVER_TAG, mEIPReceiver);
+ vpn_intent.putExtra(Constants.RECEIVER_TAG, eip_receiver);
dashboard.startService(vpn_intent);
}
@@ -267,71 +241,42 @@ public class EipFragment extends Fragment implements Observer {
}
private void handleNewState(EipStatus eip_status) {
- if (eip_status.wantsToDisconnect())
- setDisconnectedUI();
- else if (eip_status.isConnecting() || is_starting_to_connect)
- setInProgressUI(eip_status);
- else if (eip_status.isConnected())
- setConnectedUI();
- else if (eip_status.isDisconnected() && !eip_status.isConnecting())
- setDisconnectedUI();
- }
+ Context context = dashboard.getApplicationContext();
+ String error = eip_status.lastError(5, context);
- private void setConnectedUI() {
- hideProgressBar();
- adjustSwitch();
- is_starting_to_connect = false;
- status_message.setText(dashboard.getString(R.string.eip_state_connected));
- }
-
- private void setDisconnectedUI() {
- hideProgressBar();
- adjustSwitch();
- if (eip_status.errorInLast(5, dashboard.getApplicationContext())
- && !status_message.getText().toString().equalsIgnoreCase(dashboard.getString(R.string.eip_state_not_connected))) {
+ if (!error.isEmpty()) {
dashboard.showLog();
VoidVpnService.stop();
}
- status_message.setText(dashboard.getString(R.string.eip_state_not_connected));
- }
-
- private void adjustSwitch() {
- if (eip_status.isConnected() || eip_status.isConnecting() || is_starting_to_connect) {
- if (!eip_switch.isChecked()) {
- eip_switch.setChecked(true);
+ updateIcon();
+ updateButton();
+ }
+
+ private void updateIcon() {
+ if (eip_status.isConnected() || eip_status.isConnecting()) {
+ if(eip_status.isConnecting()) {
+ vpn_status_image.showProgress(true);
+ vpn_status_image.setIcon(R.drawable.ic_stat_vpn_empty_halo, R.drawable.ic_stat_vpn_empty_halo);
+ } else {
+ vpn_status_image.showProgress(false);
+ vpn_status_image.setIcon(R.drawable.ic_stat_vpn, R.drawable.ic_stat_vpn);
}
} else {
-
- if (eip_switch.isChecked()) {
- eip_switch.setChecked(false);
- }
+ vpn_status_image.setIcon(R.drawable.ic_stat_vpn_offline, R.drawable.ic_stat_vpn_offline);
+ vpn_status_image.showProgress(false);
}
}
- private void setInProgressUI(EipStatus eip_status) {
- int localizedResId = eip_status.getLocalizedResId();
- String logmessage = eip_status.getLogMessage();
- String prefix = dashboard.getString(localizedResId);
-
- showProgressBar();
- status_message.setText(prefix + " " + logmessage);
- is_starting_to_connect = false;
- adjustSwitch();
- }
-
- private void updatingCertificateUI() {
- showProgressBar();
- status_message.setText(getString(R.string.updating_certificate_message));
- }
-
- private void showProgressBar() {
- if (progress_bar != null)
- progress_bar.setVisibility(View.VISIBLE);
- }
-
- private void hideProgressBar() {
- if (progress_bar != null)
- progress_bar.setVisibility(View.GONE);
+ private void updateButton() {
+ if (eip_status.isConnected() || eip_status.isConnecting()) {
+ if(eip_status.isConnecting()) {
+ main_button.setText(dashboard.getString(android.R.string.cancel));
+ } else {
+ main_button.setText(dashboard.getString(R.string.vpn_button_turn_off));
+ }
+ } else {
+ main_button.setText(dashboard.getString(R.string.vpn_button_turn_on));
+ }
}
protected class EIPReceiver extends ResultReceiver {
@@ -374,7 +319,6 @@ public class EipFragment extends Fragment implements Observer {
case Activity.RESULT_OK:
break;
case Activity.RESULT_CANCELED:
- updatingCertificateUI();
dashboard.downloadVpnCertificate();
break;
}
@@ -394,6 +338,6 @@ public class EipFragment extends Fragment implements Observer {
public static EIPReceiver getReceiver() {
- return mEIPReceiver;
+ return eip_receiver;
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index beed7948..9ff7f1af 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -96,7 +96,7 @@ public final class EIP extends IntentService {
gateway = gateways_manager.select();
if (gateway != null && gateway.getProfile() != null) {
- mReceiver = EipFragment.getReceiver();
+ mReceiver = VpnFragment.getReceiver();
launchActiveGateway();
tellToReceiver(ACTION_START_EIP, Activity.RESULT_OK);
} else
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
index ad68f96e..4bfef1cb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
@@ -27,8 +27,11 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
private static EipStatus current_status;
private static VpnStatus.ConnectionStatus level = VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED;
- private static boolean wants_to_disconnect = false;
+ private static boolean
+ wants_to_disconnect = false,
+ is_connecting = false;
+ int last_error_line = 0;
private String state, log_message;
private int localized_res_id;
@@ -46,9 +49,9 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
@Override
public void updateState(final String state, final String logmessage, final int localizedResId, final VpnStatus.ConnectionStatus level) {
updateStatus(state, logmessage, localizedResId, level);
- if (isConnected() || isDisconnected()) {
+ if (isConnected() || isDisconnected() || wantsToDisconnect()) {
setConnectedOrDisconnected();
- } else if (isConnecting())
+ } else
setConnecting();
}
@@ -66,10 +69,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
}
public boolean isConnecting() {
- return
- !isConnected() &&
- !isDisconnected() &&
- !isPaused();
+ return is_connecting;
}
public boolean isConnected() {
@@ -85,19 +85,23 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
}
public void setConnecting() {
+ is_connecting = true;
+
wants_to_disconnect = false;
current_status.setChanged();
current_status.notifyObservers();
}
public void setConnectedOrDisconnected() {
+ is_connecting = false;
wants_to_disconnect = false;
current_status.setChanged();
current_status.notifyObservers();
}
public void setDisconnecting() {
- wants_to_disconnect = false;
+ wants_to_disconnect = true;
+ is_connecting = false;
}
public String getState() {
@@ -133,18 +137,30 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
}
public boolean errorInLast(int lines, Context context) {
- boolean result = false;
+ return !lastError(lines, context).isEmpty();
+ }
+
+ public String lastError(int lines, Context context) {
+ String error = "";
+
String[] error_keywords = {"error", "ERROR", "fatal", "FATAL"};
VpnStatus.LogItem[] log = VpnStatus.getlogbuffer();
+ if(log.length < last_error_line)
+ last_error_line = 0;
String message = "";
for (int i = 1; i <= lines && log.length > i; i++) {
- message = log[log.length - i].getString(context);
+ int line = log.length - i;
+ VpnStatus.LogItem log_item = log[line];
+ message = log_item.getString(context);
for (int j = 0; j < error_keywords.length; j++)
- if (message.contains(error_keywords[j]))
- result = true;
+ if (message.contains(error_keywords[j]) && line > last_error_line) {
+ error = message;
+ last_error_line = line;
+ }
}
- return result;
+
+ return error;
}
@Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 1c64328e..f41049c5 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -16,19 +16,27 @@
*/
package se.leap.bitmaskclient.eip;
-import android.content.*;
+import android.content.Context;
+import android.content.SharedPreferences;
-import com.google.gson.*;
-import com.google.gson.reflect.*;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
-import org.json.*;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
-import java.lang.reflect.*;
-import java.util.*;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
-import de.blinkt.openvpn.*;
-import de.blinkt.openvpn.core.*;
-import se.leap.bitmaskclient.*;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.Connection;
+import de.blinkt.openvpn.core.ProfileManager;
+import se.leap.bitmaskclient.Provider;
/**
* @author parmegv
@@ -65,7 +73,7 @@ public class GatewaysManager {
}
public void addFromString(String gateways) {
- List<Gateway> gateways_list = new ArrayList<Gateway>();
+ List<Gateway> gateways_list = new ArrayList<>();
try {
gateways_list = new Gson().fromJson(gateways, list_type);
} catch (JsonSyntaxException e) {
@@ -75,7 +83,6 @@ public class GatewaysManager {
if (gateways_list != null) {
for (Gateway gateway : gateways_list)
addGateway(gateway);
- this.gateways.addAll(gateways_list);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
index dac92fe2..cbf0fed2 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java
@@ -50,6 +50,10 @@ public class VoidVpnService extends VpnService {
closeFd();
}
+ public static boolean isRunning() throws NullPointerException {
+ return thread.isAlive() && fd != null;
+ }
+
private static void closeFd() {
try {
if (fd != null)
diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java
new file mode 100644
index 00000000..d1c56dee
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/FabButton.java
@@ -0,0 +1,28 @@
+package se.leap.bitmaskclient.userstatus;
+
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import mbanje.kurt.fabbutton.CircleImageView;
+import se.leap.bitmaskclient.R;
+
+public class FabButton extends mbanje.kurt.fabbutton.FabButton {
+
+
+ public FabButton(Context context) {
+ super(context);
+ }
+
+ public FabButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public FabButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ private CircleImageView getImage() {
+ return (CircleImageView) findViewById(R.id.fabbutton_circle);
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java
index e92c6b7b..7dbbe059 100644
--- a/app/src/main/java/se/leap/bitmaskclient/SessionDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.userstatus;
import android.app.*;
import android.content.*;
@@ -23,6 +23,9 @@ import android.view.*;
import android.widget.*;
import butterknife.*;
+import se.leap.bitmaskclient.VpnFragment;
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.R;
/**
* Implements the log in dialog, currently without progress dialog.
@@ -56,8 +59,18 @@ public class SessionDialog extends DialogFragment {
private static boolean is_eip_pending = false;
- public SessionDialog() {
- setArguments(Bundle.EMPTY);
+ public static SessionDialog getInstance(Provider provider, Bundle arguments) {
+ SessionDialog dialog = new SessionDialog();
+ if (provider.getName().equalsIgnoreCase("riseup")) {
+ arguments =
+ arguments == Bundle.EMPTY ?
+ new Bundle() : arguments;
+ arguments.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true);
+ }
+ if (arguments != null && !arguments.isEmpty()) {
+ dialog.setArguments(arguments);
+ }
+ return dialog;
}
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
@@ -68,7 +81,7 @@ public class SessionDialog extends DialogFragment {
ButterKnife.inject(this, view);
Bundle arguments = getArguments();
- if (arguments != Bundle.EMPTY) {
+ if (arguments != Bundle.EMPTY && arguments != null) {
setUp(arguments);
}
@@ -100,7 +113,7 @@ public class SessionDialog extends DialogFragment {
}
private void setUp(Bundle arguments) {
- is_eip_pending = arguments.getBoolean(EipFragment.IS_PENDING, false);
+ is_eip_pending = arguments.getBoolean(VpnFragment.IS_PENDING, false);
if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString()))
password_field.setError(getString(R.string.error_not_valid_password_user_message));
else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) {
@@ -114,9 +127,10 @@ public class SessionDialog extends DialogFragment {
if (arguments.containsKey(ERRORS.USERNAME_MISSING.toString())) {
username_field.setError(getString(R.string.username_ask));
}
- if (arguments.containsKey(getString(R.string.user_message)))
+ if (arguments.containsKey(getString(R.string.user_message))) {
user_message.setText(arguments.getString(getString(R.string.user_message)));
- else if (user_message.getVisibility() != TextView.VISIBLE)
+ user_message.setVisibility(View.VISIBLE);
+ } else if (user_message.getVisibility() != TextView.VISIBLE)
user_message.setVisibility(View.GONE);
if (!username_field.getText().toString().isEmpty() && password_field.isFocusable())
@@ -151,8 +165,9 @@ public class SessionDialog extends DialogFragment {
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
+
try {
- interface_with_Dashboard = (SessionDialogInterface) activity;
+ interface_with_Dashboard = (SessionDialogInterface) activity.getFragmentManager().findFragmentById(R.id.user_status_fragment);;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement LogInDialogListener");
diff --git a/app/src/main/java/se/leap/bitmaskclient/User.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java
index 4bbd9a91..64ce0629 100644
--- a/app/src/main/java/se/leap/bitmaskclient/User.java
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/User.java
@@ -14,15 +14,18 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package se.leap.bitmaskclient;
+package se.leap.bitmaskclient.userstatus;
+
+import se.leap.bitmaskclient.LeapSRPSession;
public class User {
- private static String user_name = "You";
+ private static String user_name;
private static User user;
- public static User getInstance() {
+ public static User init(String default_username) {
if (user == null) {
user = new User();
+ user.setUserName(default_username);
}
return user;
}
@@ -31,8 +34,7 @@ public class User {
User.user_name = user_name;
}
- private User() {
- }
+ private User() { }
public static String userName() {
return user_name;
diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java
new file mode 100644
index 00000000..90ad0ffd
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatus.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2013 LEAP Encryption Access Project and contributers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package se.leap.bitmaskclient.userstatus;
+
+import android.content.res.*;
+
+import java.util.*;
+
+import se.leap.bitmaskclient.R;
+
+public class UserStatus extends Observable {
+ public static String TAG = UserStatus.class.getSimpleName();
+ private static UserStatus current_status;
+ private static Resources resources;
+
+ public enum SessionStatus {
+ LOGGED_IN,
+ LOGGED_OUT,
+ NOT_LOGGED_IN,
+ DIDNT_LOG_OUT,
+ LOGGING_IN,
+ LOGGING_OUT,
+ SIGNING_UP;
+
+ @Override
+ public String toString() {
+ int id = 0;
+ if(this == SessionStatus.LOGGED_IN)
+ id = R.string.logged_in_user_status;
+ else if(this == SessionStatus.LOGGED_OUT)
+ id = R.string.logged_out_user_status;
+ else if(this == SessionStatus.NOT_LOGGED_IN)
+ id = R.string.not_logged_in_user_status;
+ else if(this == SessionStatus.DIDNT_LOG_OUT)
+ id = R.string.didnt_log_out_user_status;
+ else if(this == SessionStatus.LOGGING_IN)
+ id = R.string.logging_in_user_status;
+ else if(this == SessionStatus.LOGGING_OUT)
+ id = R.string.logging_out_user_status;
+ else if(this == SessionStatus.SIGNING_UP)
+ id = R.string.signingup_message;
+
+ return resources.getString(id);
+ }
+ }
+
+ private static SessionStatus session_status = SessionStatus.LOGGED_OUT;
+
+ public static UserStatus getInstance(Resources resources) {
+ if (current_status == null) {
+ current_status = new UserStatus(resources);
+ }
+ return current_status;
+ }
+
+ private UserStatus(Resources resources) {
+ UserStatus.resources = resources;
+ }
+
+ private void sessionStatus(SessionStatus session_status) {
+ this.session_status = session_status;
+ }
+
+ public SessionStatus sessionStatus() {
+ return session_status;
+ }
+
+ public boolean inProgress() {
+ return session_status == SessionStatus.LOGGING_IN
+ || session_status == SessionStatus.LOGGING_OUT;
+ }
+
+ public boolean isLoggedIn() {
+ return session_status == SessionStatus.LOGGED_IN;
+ }
+
+ public boolean isLoggedOut() {
+ return session_status == SessionStatus.LOGGED_OUT;
+ }
+
+ public boolean notLoggedIn() {
+ return session_status == SessionStatus.NOT_LOGGED_IN;
+ }
+
+ public boolean didntLogOut() {
+ return session_status == SessionStatus.DIDNT_LOG_OUT;
+ }
+
+ public static void updateStatus(SessionStatus session_status, Resources resources) {
+ current_status = getInstance(resources);
+ current_status.sessionStatus(session_status);
+ current_status.setChanged();
+ current_status.notifyObservers();
+ }
+
+ @Override
+ public String toString() {
+ String user_session_status = User.userName();
+
+ String default_username = resources.getString(R.string.default_username, "");
+ if(user_session_status.isEmpty() && !default_username.equalsIgnoreCase("null")) user_session_status = default_username;
+ user_session_status += " " + session_status.toString();
+
+ user_session_status = user_session_status.trim();
+ if(User.userName().isEmpty())
+ user_session_status = capitalize(user_session_status);
+ return user_session_status;
+ }
+
+ private String capitalize(String to_be_capitalized) {
+ return to_be_capitalized.substring(0,1).toUpperCase() + to_be_capitalized.substring(1);
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java
new file mode 100644
index 00000000..20189904
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java
@@ -0,0 +1,181 @@
+package se.leap.bitmaskclient.userstatus;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import butterknife.ButterKnife;
+import butterknife.InjectView;
+import butterknife.OnClick;
+import se.leap.bitmaskclient.Dashboard;
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.ProviderAPI;
+import se.leap.bitmaskclient.ProviderAPICommand;
+import se.leap.bitmaskclient.ProviderAPIResultReceiver;
+import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.eip.EipStatus;
+
+public class UserStatusFragment extends Fragment implements Observer, SessionDialog.SessionDialogInterface {
+
+ public static String TAG = UserStatusFragment.class.getSimpleName();
+ private static Dashboard dashboard;
+ private ProviderAPIResultReceiver providerAPI_result_receiver;
+
+ @InjectView(R.id.user_status_username)
+ TextView username;
+ @InjectView(R.id.user_status_icon)
+ FabButton icon;
+ @InjectView(R.id.user_status_button)
+ Button button;
+
+ private UserStatus status;
+ private boolean allows_registration = false;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ status = UserStatus.getInstance(getResources());
+ status.addObserver(this);
+ }
+
+ @Override
+ public void onSaveInstanceState(@NotNull Bundle outState) {
+ if (username != null && username.getVisibility() == TextView.VISIBLE)
+ outState.putSerializable(UserStatus.TAG, status.sessionStatus());
+
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View view = inflater.inflate(R.layout.user_session_fragment, container, false);
+ ButterKnife.inject(this, view);
+
+ Bundle arguments = getArguments();
+ allows_registration = arguments.getBoolean(Provider.ALLOW_REGISTRATION);
+ handleNewStatus(status);
+
+ return view;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ dashboard = (Dashboard) activity;
+
+ providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), dashboard);
+ }
+
+ public void restoreSessionStatus(Bundle savedInstanceState) {
+ if (savedInstanceState != null)
+ if (savedInstanceState.containsKey(UserStatus.TAG)) {
+ UserStatus.SessionStatus status = (UserStatus.SessionStatus) savedInstanceState.getSerializable(UserStatus.TAG);
+ this.status.updateStatus(status, getResources());
+ }
+ }
+
+ @OnClick(R.id.user_status_button)
+ public void handleButton() {
+ android.util.Log.d(TAG, status.toString());
+ if(status.isLoggedIn())
+ logOut();
+ else if(status.isLoggedOut())
+ dashboard.sessionDialog(Bundle.EMPTY);
+ else if(status.inProgress())
+ cancelLoginOrSignup();
+ }
+
+ @Override
+ public void update(Observable observable, Object data) {
+ if (observable instanceof UserStatus) {
+ final UserStatus status = (UserStatus) observable;
+ dashboard.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ handleNewStatus(status);
+ }
+ });
+ }
+ }
+
+ private void handleNewStatus(UserStatus status) {
+ this.status = status;
+ if (allows_registration) {
+ if (this.status.inProgress())
+ showUserSessionProgressBar();
+ else
+ hideUserSessionProgressBar();
+ changeMessage();
+ updateButton();
+ }
+ }
+
+ private void showUserSessionProgressBar() {
+ icon.showProgress(true);
+ }
+
+ private void hideUserSessionProgressBar() {
+ icon.showProgress(false);
+ }
+
+ private void changeMessage() {
+ final String message = User.userName();
+ username.setText(message);
+ }
+
+ private void updateButton() {
+ if(status.isLoggedIn() || status.didntLogOut())
+ button.setText(dashboard.getString(R.string.logout_button));
+ else if(allows_registration) {
+ if (status.isLoggedOut() || status.notLoggedIn())
+ button.setText(dashboard.getString(R.string.login_button));
+ else if (status.inProgress())
+ button.setText(dashboard.getString(android.R.string.cancel));
+ }
+ }
+
+
+ @Override
+ public void signUp(String username, String password) {
+ User.setUserName(username);
+ Bundle parameters = bundlePassword(password);
+ ProviderAPICommand.execute(parameters, ProviderAPI.SIGN_UP, providerAPI_result_receiver);
+ }
+
+ @Override
+ public void logIn(String username, String password) {
+ User.setUserName(username);
+ Bundle parameters = bundlePassword(password);
+ ProviderAPICommand.execute(parameters, ProviderAPI.LOG_IN, providerAPI_result_receiver);
+ }
+
+ public void logOut() {
+ android.util.Log.d(TAG, "Log out");
+ ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.LOG_OUT, providerAPI_result_receiver);
+ }
+
+ public void cancelLoginOrSignup() {
+ EipStatus.getInstance().setConnectedOrDisconnected();
+ }
+
+ private Bundle bundlePassword(String password) {
+ Bundle parameters = new Bundle();
+ if (!password.isEmpty())
+ parameters.putString(SessionDialog.PASSWORD, password);
+ return parameters;
+ }
+}
diff --git a/app/src/main/res/drawable-hdpi/ic_account_circle.png b/app/src/main/res/drawable-hdpi/ic_account_circle.png
new file mode 100644
index 00000000..db02b319
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_account_circle.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_account_circle.png b/app/src/main/res/drawable-mdpi/ic_account_circle.png
new file mode 100644
index 00000000..2489c703
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_account_circle.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_account_circle.png b/app/src/main/res/drawable-xhdpi/ic_account_circle.png
new file mode 100644
index 00000000..848a4fda
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_account_circle.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_circle.png b/app/src/main/res/drawable-xxhdpi/ic_account_circle.png
new file mode 100644
index 00000000..a886b553
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_account_circle.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png b/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png
new file mode 100644
index 00000000..c8feac66
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_account_circle.png
Binary files differ
diff --git a/app/src/main/res/layout-xlarge/dashboard.xml b/app/src/main/res/layout-xlarge/dashboard.xml
index 268bd3f9..3c93a04c 100644
--- a/app/src/main/res/layout-xlarge/dashboard.xml
+++ b/app/src/main/res/layout-xlarge/dashboard.xml
@@ -5,80 +5,45 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginLeft="10sp"
+ android:layout_marginStart="10sp"
android:layout_marginTop="10sp"
tools:context=".Dashboard" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="42dp"
- android:background="?android:attr/selectableItemBackground" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingLeft="10dp" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:text="@string/provider_label"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="32sp" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingLeft="32dp" >
- <TextView
- android:id="@+id/providerName"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:text="@string/provider_label_none"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- </LinearLayout>
- </LinearLayout>
+ <TextView
+ android:id="@+id/providerName"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dp"
+ android:layout_marginStart="32dp"
+ android:textSize="48sp"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical"
+ android:text="@string/provider_label_none"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="32dp">
- <ProgressBar
- android:id="@+id/user_session_status_progress"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:indeterminate="true"
- android:visibility="gone"/>
- <TextView
- android:id="@+id/user_session_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:layout_marginLeft="10dp"
- android:ellipsize="marquee"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
+ android:layout_marginLeft="32dp"
+ android:layout_marginStart="32dp">
+ <ProgressBar
+ android:id="@+id/user_session_status_progress"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:indeterminate="true"
+ android:visibility="gone"/>
+ <TextView
+ android:id="@+id/user_session_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:layout_marginLeft="10dp"
+ android:layout_marginStart="10dp"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
</LinearLayout>
-
- <View
- android:layout_width="wrap_content"
- android:layout_height="1dp"
- android:layout_marginBottom="7dp"
- android:background="@android:drawable/divider_horizontal_bright" />
<LinearLayout
android:id="@+id/servicesCollection"
diff --git a/app/src/main/res/layout-xlarge/eip_service_fragment.xml b/app/src/main/res/layout-xlarge/eip_service_fragment.xml
index 38b6aca3..a9f01fb8 100644
--- a/app/src/main/res/layout-xlarge/eip_service_fragment.xml
+++ b/app/src/main/res/layout-xlarge/eip_service_fragment.xml
@@ -3,54 +3,53 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:layout_marginLeft="20dp" >
+ android:layout_marginLeft="20dp"
+ android:layout_marginStart="20dp">
<TextView
android:id="@+id/eipLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
- android:clickable="true"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
android:text="@string/eip_service_label"
android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="26sp" />
+ android:textSize="24sp"/>
- <Switch
- android:id="@+id/eipSwitch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_marginRight="10dp"
- android:height="26dp"/>
-
- <ProgressBar
- android:id="@+id/eipProgress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@android:style/Widget.Holo.ProgressBar.Horizontal"
- android:indeterminate="true"
- android:visibility="gone"
- android:layout_below="@id/eipLabel"
- android:layout_marginLeft="15dp"
- android:layout_marginRight="15dp" />
- <TextView
- android:id="@+id/status_message"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:orientation="horizontal"
android:layout_below="@+id/eipLabel"
- android:paddingBottom="10dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:paddingTop="10dp"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:clickable="true"
- android:text="@string/eip_state_not_connected"
- android:textSize="16sp" />
+ android:layout_centerInParent="true">
+ <Button
+ android:id="@+id/vpn.main.button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginLeft="24dp"
+ android:textSize="32sp"
+ />
+ <view
+ android:id="@+id/vpn.Status.Image"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:color="@android:color/holo_blue_dark"
+ class="mbanje.kurt.fabbutton.FabButton"
+ android:layout_gravity="center"
+ android:visibility="visible"
+ android:indeterminate="true"
+ android:max="100"
+ fbb_autoStart="true"
+ fbb_progressColor="#ff170aff"
+ fbb_progressWidthRatio="0.1"
+ android:layout_marginStart="24dp"
+ android:layout_marginLeft="24dp"
+ />
+ </LinearLayout>
</RelativeLayout>
diff --git a/app/src/main/res/layout-xlarge/user_session_fragment.xml b/app/src/main/res/layout-xlarge/user_session_fragment.xml
new file mode 100644
index 00000000..30969219
--- /dev/null
+++ b/app/src/main/res/layout-xlarge/user_session_fragment.xml
@@ -0,0 +1,55 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="30dp"
+ android:layout_marginLeft="60dp"
+ android:layout_marginStart="60dp"
+ android:orientation="vertical"
+ tools:context="se.leap.bitmaskclient.userstatus.UserStatusFragment">
+
+ <TextView
+ android:id="@+id/user.status.username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:layout_marginRight="60dp"
+ android:layout_marginEnd="60dp"
+ android:layout_gravity="center"
+ android:textSize="46sp"
+ android:text="@string/default_username"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <LinearLayout
+ android:id="@+id/user.status.buttonAndIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
+
+ <Button
+ android:id="@+id/user.status.button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="24sp"
+ />
+
+ <view
+ android:id="@+id/user.status.icon"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_marginLeft="26dp"
+ android:layout_marginStart="26dp"
+ android:background="@android:color/transparent"
+ android:color="@android:color/holo_blue_dark"
+ class="mbanje.kurt.fabbutton.FabButton"
+ android:layout_gravity="center"
+ android:visibility="visible"
+ android:indeterminate="true"
+ android:max="100"
+ fbb_autoStart="true"
+ fbb_progressColor="#ff170aff"
+ fbb_progressWidthRatio="0.3"
+ />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/app/src/main/res/layout/dashboard.xml b/app/src/main/res/layout/dashboard.xml
index f4269fe2..6a9bbe97 100644
--- a/app/src/main/res/layout/dashboard.xml
+++ b/app/src/main/res/layout/dashboard.xml
@@ -5,61 +5,30 @@
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Dashboard" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="40dp"
- android:background="?android:attr/selectableItemBackground" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dp"
- android:ellipsize="marquee"
- android:singleLine="true"
- android:text="@string/provider_label"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/providerName"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="28sp"
- android:layout_marginLeft="10dp"
- android:ellipsize="marquee"
- android:singleLine="true"
- android:text="@string/provider_label_none"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/providerName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"
+ android:layout_marginStart="10dp"
+ android:textSize="26sp"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:text="@string/provider_label_none"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<LinearLayout
+ android:id="@+id/user.status.fragment"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ProgressBar
- android:id="@+id/user_session_status_progress"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:indeterminate="true"
- android:visibility="gone"/>
- <TextView
- android:id="@+id/user_session_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:layout_marginLeft="10dp"
- android:ellipsize="marquee"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
- </LinearLayout>
-
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"/>
+
<LinearLayout
android:id="@+id/servicesCollection"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.11"
- android:orientation="vertical" >
- </LinearLayout>
-
+ android:orientation="vertical" />
</LinearLayout>
diff --git a/app/src/main/res/layout/eip_service_fragment.xml b/app/src/main/res/layout/eip_service_fragment.xml
index 64d22147..06b514d3 100644
--- a/app/src/main/res/layout/eip_service_fragment.xml
+++ b/app/src/main/res/layout/eip_service_fragment.xml
@@ -2,50 +2,49 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="10dp" >
+ android:layout_marginTop="10dp">
<TextView
android:id="@+id/eipLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
android:layout_marginLeft="10dp"
- android:clickable="true"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
android:text="@string/eip_service_label"
- android:textAppearance="?android:attr/textAppearanceLarge" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <Switch
- android:id="@+id/eipSwitch"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_marginRight="10dp" />
+ android:orientation="horizontal"
+ android:layout_below="@+id/eipLabel"
+ android:layout_centerInParent="true">
- <ProgressBar
- android:id="@+id/eipProgress"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@android:style/Widget.Holo.ProgressBar.Horizontal"
- android:indeterminate="true"
- android:visibility="gone"
- android:layout_below="@id/eipLabel"
- android:layout_marginLeft="15dp"
- android:layout_marginRight="15dp" />
-
- <TextView
- android:id="@+id/status_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@id/eipProgress"
- android:layout_centerVertical="true"
- android:paddingTop="5dp"
- android:paddingBottom="10dp"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:clickable="true"
- android:text="@string/eip_state_not_connected" />
+ <Button
+ android:id="@+id/vpn.main.button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="12sp"
+ />
+ <view
+ android:id="@+id/vpn.Status.Image"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginLeft="3dp"
+ android:layout_marginStart="3dp"
+ android:color="@android:color/holo_blue_dark"
+ class="mbanje.kurt.fabbutton.FabButton"
+ android:layout_gravity="center"
+ android:visibility="visible"
+ android:indeterminate="true"
+ android:max="100"
+ fbb_autoStart="true"
+ fbb_progressColor="#ff170aff"
+ fbb_progressWidthRatio="0.1"
+ />
+ </LinearLayout>
</RelativeLayout>
diff --git a/app/src/main/res/layout/user_session_fragment.xml b/app/src/main/res/layout/user_session_fragment.xml
new file mode 100644
index 00000000..d33f9b9a
--- /dev/null
+++ b/app/src/main/res/layout/user_session_fragment.xml
@@ -0,0 +1,46 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginLeft="20dp"
+ android:layout_marginStart="20dp"
+ tools:context="se.leap.bitmaskclient.userstatus.UserStatusFragment">
+
+ <TextView
+ android:id="@+id/user.status.username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:layout_marginRight="15dp"
+ android:layout_marginEnd="20dp"
+ android:textSize="20sp"
+ android:text="@string/default_username"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <Button
+ android:id="@+id/user.status.button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ />
+
+ <view
+ android:id="@+id/user.status.icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginLeft="9dp"
+ android:layout_marginStart="9dp"
+ android:shadowRadius="0"
+ android:src="@drawable/ic_account_circle"
+ android:color="@android:color/transparent"
+ class="se.leap.bitmaskclient.userstatus.FabButton"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ app:fbb_progressColor="@android:color/holo_green_dark"
+ app:fbb_progressWidthRatio="0.2"
+ app:fbb_showShadow="false"
+ />
+
+</LinearLayout>
diff --git a/app/src/main/res/menu/client_dashboard.xml b/app/src/main/res/menu/client_dashboard.xml
index 9bc39d7b..e0336cc0 100644
--- a/app/src/main/res/menu/client_dashboard.xml
+++ b/app/src/main/res/menu/client_dashboard.xml
@@ -15,15 +15,5 @@
android:id="@+id/signup_button"
android:title="@string/signup_button"
android:visible="false"/>
- <item
- android:id="@+id/login_button"
- android:showAsAction="ifRoom"
- android:title="@string/login_button"
- android:visible="false"/>
- <item
- android:id="@+id/logout_button"
- android:showAsAction="ifRoom"
- android:title="@string/logout_button"
- android:visible="false"/>
</menu>
diff --git a/app/src/main/res/values-ca/strings-icsopenvpn.xml b/app/src/main/res/values-ca/strings-icsopenvpn.xml
index ce7b8919..16147643 100755
--- a/app/src/main/res/values-ca/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ca/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Adreá del servidor:</string>
diff --git a/app/src/main/res/values-cs/strings-icsopenvpn.xml b/app/src/main/res/values-cs/strings-icsopenvpn.xml
index 87a6bed1..12837f13 100755
--- a/app/src/main/res/values-cs/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-cs/strings-icsopenvpn.xml
@@ -1,16 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Adresa serveru:</string>
<string name="port">Port serveru:</string>
- <string name="location">Lokace</string>
+ <string name="location">Cesta</string>
<string name="cant_read_folder">Nelze přečíst adresář</string>
<string name="select">Zvolit</string>
<string name="cancel">Storno</string>
@@ -348,4 +346,24 @@
<string name="advanced_settings">Pokročilé nastavení</string>
<string name="payload_options">Možnosti dat</string>
<string name="tls_settings">Nastevení TLS</string>
+ <string name="no_remote_defined">Nedefinovaná protistrana</string>
+ <string name="duplicate_vpn">Duplicitní VPN profil</string>
+ <string name="duplicate_profile_title">Duplicitní profil: %s</string>
+ <string name="show_log">Zobrazit log</string>
+ <string name="faq_androids_clients_title">Rozdíly mezi OpenVPN klienty pro Android</string>
+ <string name="ignore_multicast_route">Ignorovat vícesměrovou trasu: %s</string>
+ <string name="ab_only_cidr">Android podporuje ve VPN síti podporuje pouze CIDR trasy. Protože ne-CIDR trasy nejsou téměř nikdy používány, OpenVPN pro Android použije /32 pro trasy, které nejsou CIDR a zobrazí varování.</string>
+ <string name="ab_tethering_44">Sdílení připojení funguje během aktivního VPN spojení. Sdílené připojení NEpoužije VPN.</string>
+ <string name="ab_kitkat_mss">Dřívější KitKat verze nastavovaly špatnou hodnotu MSS na TCP spojení (#61948). OpenVPN automaticky zapne mssfix možnost pro obejití chyby.</string>
+ <string name="ab_secondary_users">VPN vůbec nefunguje pro vedlejší uživatele.</string>
+ <string name="ab_only_cidr_title">Ne-CIDR trasy</string>
+ <string name="ab_proxy_title">Proxy chování pro VPN</string>
+ <string name="ab_lollipop_reinstall_title">Přeinstalování VPN aplikací</string>
+ <string name="version_upto">%s a starší</string>
+ <string name="copy_of_profile">Kopie %s</string>
+ <string name="ab_not_route_to_vpn_title">Trasa k nastavené IP adrese</string>
+ <string name="ab_kitkat_mss_title">Špatná hodnota MSS pro VPN spojení</string>
+ <string name="ab_secondary_users_title">Vedlejší uživaté tabletu</string>
+ <string name="custom_connection_options">Vlastní možnosti</string>
+ <string name="remove_connection_entry">Odstranit položku připojení</string>
</resources>
diff --git a/app/src/main/res/values-de/strings-icsopenvpn.xml b/app/src/main/res/values-de/strings-icsopenvpn.xml
index ba667502..bb22c373 100755
--- a/app/src/main/res/values-de/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-de/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Server:</string>
@@ -89,7 +87,7 @@
<string name="default_route_summary">Leitet allen Internet Verkehr über das VPN</string>
<string name="use_default_title">Benutze Default Route</string>
<string name="custom_route_message">Benutze eigene Routen. Geben Sie Zielnetzwerk im CIDR Format an. Z.b. \"10.0.0.0/8 2002::/16\" würde die Netzwerke 10.0.0.0/8 und 2002::/16 über das VPN routen.</string>
- <string name="custom_route_message_excluded">Netze, die nicht über das VPN geleitet werden sollen. Nutzt die gleiche Syntax wie die eigenen Routen.</string>
+ <string name="custom_route_message_excluded">Routen, die NICHT über das VPN geleitet werden sollen. Verwendet die gleiche Syntax wie bei den eigenen Routen.</string>
<string name="custom_routes_title">Eigene Routen</string>
<string name="custom_routes_title_excluded">Ausgeschlossene Netze</string>
<string name="log_verbosity_level">Log Detail Level</string>
@@ -195,7 +193,7 @@
<string name="export_config_title">ICS OpenVPN Konfiguration</string>
<string name="warn_no_dns">Es werden keine DNS Server für die VPN Verbindung genutzt. Die Namensauflösung wird möglicherweise nicht funktionieren. Ziehen Sie in Erwähung selbst DNS Server in den Optionen zu setzen. Beachten Sie weiterhin, dass Android die Proxyeinstellungen für Handy/WLAN weiterhin benutzt, falls keine DNS Server für das VPN festgelegt sind.</string>
<string name="dns_add_error">Konnte den DNS Server \"%1$s\" nicht hinzufügen, da das System ihn zurückweist mit %2$s</string>
- <string name="ip_add_error">Konnte nicht die IP Adresse \"%1$s\" nicht setzen. Fehlermeldung des Systems: %2$s</string>
+ <string name="ip_add_error">Konnte die IP Adresse \"%1$s\" nicht setzen, abgelehnt vom System: %2$s</string>
<string name="faq_howto">&lt;p&gt;Benutzen Sie eine funktionierende Konfiguration (getestet auf einem Computer, oder von Ihrer Organisation/Ihrem Provider bereitgestellt)&lt;/p&gt;&lt;p&gt;Falls Sie nur eine einzelne Datei benötigen, können Sie sich diese als Email-Anhang zuschicken. Falls Ihre OpenVPN Konfiguration aus mehreren Dateien besteht, müssen Sie alle Dateien auf die SD Karte kopieren.&lt;/p&gt;&lt;p&gt;Klicken Sie auf den Email Anhang im Android Mail Programm bzw. benutzen Sie das Ordner Symbol in der VPN Liste und wählen Sie die .ovpn bzw. .conf Konfigurationsdatei aus.&lt;/p&gt;&lt;p&gt;Falls der Import fehlende Dateien anmerkt, kopieren Sie diese auf die SD Karte und starten den Import erneut.&lt;/p&gt;&lt;p&gt;Benutzen Sie anschließend das Speichern Symbol um das VPN zur VPN Liste hinzuzufügen&lt;/p&gt;&lt;p&gt;Tippen Sie den Namen des VPNs an, um das VPN zu starten&lt;/p&gt;&lt;p&gt;Achten Sie auf Fehler und Warnungen im Verbindungslog.&lt;/p&gt; </string>
<string name="faq_howto_title">Schnellstart</string>
<string name="setting_loadtun_summary">Versuche das tun.ko Kernel Modul zu laden. Benötigt root.</string>
@@ -259,7 +257,7 @@
<string name="start_vpn_title">Verbinde mit VPN %s</string>
<string name="start_vpn_ticker">Verbinde mit VPN %s</string>
<string name="jelly_keystore_alphanumeric_bug">Einige Versionen von Android 4.1 haben Probleme, wenn der Name des im Zertifikat Keystore gespeicherten Zertifikates nicht alphanumerische Zeichen (wie Leerzeichen, Unterstriche oder Bindestriche) enthält. Probieren Sie das Sie das Zertifikat mit einem Namen ohne Sonderzeichen zu importieren.</string>
- <string name="encryption_cipher">Verschlüsslungsalgorithmus</string>
+ <string name="encryption_cipher">Verschlüsselungsalgorithmus</string>
<string name="packet_auth">Packetauthentifizierung</string>
<string name="auth_dialog_title">Geben Sie den Authentifizierungsalgorithmus an</string>
<string name="mobile_info_extended">Modell %1$s (%2$s) %3$s, Android API %4$d, version %5$s, %6$s</string>
@@ -282,7 +280,7 @@
<string name="no_external_app_allowed">Keine App für die Verwendung der API freigegeben</string>
<string name="allowed_apps">Freigegebene Apps: %s</string>
<string name="clearappsdialog">Liste der freigegeben externen Apps löschen? \nAktuelle Liste der freigegebenen Apps:\n\n%s</string>
- <string name="screenoff_summary">Pausiert das VPN, wenn der Bildschirm aus ist und weniger als 64 kB in 60 Sekunden übertragen wurden. Falls die Option \"Persistentes tun Device\" ausgewählt wird durch das Pausieren des VPNs das Gerät KEINE Netzwerkverbindung haben. Ohne die \"Persistentes tun Device\" Option, benutzt das Gerät die normal (ungesicherte) Internetverbindung, wenn das VPN pausiert wird.</string>
+ <string name="screenoff_summary">Pausiert das VPN, wenn der Bildschirm aus ist und weniger als 64 kB in 60 Sekunden übertragen wurden. Falls die Option \"Persistentes tun Device\" ausgewählt ist, wird durch das Pausieren des VPNs das Gerät KEINE Netzwerkverbindung haben. Ohne die \"Persistentes tun Device\" Option, benutzt das Gerät die normal (ungesicherte) Internetverbindung, wenn das VPN pausiert wird.</string>
<string name="screenoff_title">Bei ausgeschalteten Bildschirm VPN Verbindung pausieren</string>
<string name="screenoff_pause">Pausiere VPN Verbindung da weniger als %1$s in %2$ss.</string>
<string name="screen_nopersistenttun">Warnung: Persistentes tun Device für dieses VPN nicht aktiviert. Der Netzwerkverkehr nutzt die normale Internet Verbindung, wenn der Bildschirm aus ist.</string>
@@ -298,7 +296,7 @@
<string name="allow_vpn_changes">Änderungen an VPN-profilen zulassen</string>
<string name="hwkeychain">Im Hardware Keystore gespeichert:</string>
<string name="permission_icon_app">Symbol der Anwendung, die versucht OpenVPN für Android zu kontrollieren</string>
- <string name="faq_vpndialog43">Beginnend mit Android 4.3 wird der VPN-Bestätigungsdialog vor \"überlappenden Anwendungen\" geschützt. Dadurch kann es vorkommen, dass der Dialog nicht auf Eingaben reagiert. Eine Anwendung benutzen, die Overlays verwendet, kann es dieses Verhalten verursachen. Sollten Sie die verursachende Anwendung finden, kontaktieren Sie dessen Author. Dieses Problem betrifft alle VPN-Anwendungen ab Android 4.3. Siehe auch &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\" &gt; Issue 185 &lt;a&gt; für zusätzliche Details \"</string>
+ <string name="faq_vpndialog43">Beginnend mit Android 4.3 wird der VPN-Bestätigungsdialog vor \"überlappenden Anwendungen\" geschützt. Dadurch kann es vorkommen, dass der Dialog nicht auf Eingaben reagiert. Eine Anwendung benutzen, die Overlays verwendet, kann dieses Verhalten verursachen. Sollten Sie solch eine verursachende Anwendung finden, kontaktieren Sie dessen Entwickler. Dieses Problem betrifft alle VPN-Anwendungen ab Android 4.3. Siehe auch &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\" &gt; Issue 185 &lt;a&gt; für zusätzliche Details \"</string>
<string name="faq_vpndialog43_title">VPN-Bestätigungsdialog ab Android 4.3</string>
<string name="donatePlayStore">Alternativ können Sie mir per Play Store Geld zukommen lassen:</string>
<string name="thanks_for_donation">Vielen Dank für die %s Spende!</string>
@@ -332,8 +330,8 @@
<string name="client_behaviour">Client-Verhalten</string>
<string name="clear_external_apps">Widerrufe Berechtigungen OpenVPN zu steuern</string>
<string name="loading">Wird geladen&#8230;</string>
- <string name="allowed_vpn_apps_info">Apps erlaubt für das VPN: %1$s</string>
- <string name="disallowed_vpn_apps_info">Apps, die nicht das VPN nutzen: %1$s</string>
+ <string name="allowed_vpn_apps_info">Erlaubte Apps für das VPN: %1$s</string>
+ <string name="disallowed_vpn_apps_info">Verbotene Apps für das VPN: %1$s</string>
<string name="app_no_longer_exists">Anwendung mit Paketnamen \'%s\' ist nicht mehr installiert, wird von der Liste der erlaubten/nicht erlaubten VPN Anwendungen gelöscht.</string>
<string name="vpn_disallow_radio">VPN für alle Anwendung ausgenommen den ausgewählten</string>
<string name="vpn_allow_radio">VPN nur für die ausgewählten Anwendungen</string>
@@ -351,4 +349,28 @@
<string name="no_remote_defined">Keine Server definiert</string>
<string name="duplicate_vpn">VPN Profil duplizieren</string>
<string name="duplicate_profile_title">VPN Profil duplizieren: %s</string>
+ <string name="show_log">Log anzeigen</string>
+ <string name="faq_android_clients">Es gibt es mehrere OpenVPN-Clients für Android. Die am häufigsten genutzten sind OpenVPN für Android (dieser Client), OpenVPN Connect und OpenVPN Settings. &lt;p&gt; Die Clients in zwei Gruppen eingeteilt werden können: OpenVPN für Android und OpenVPN Connect verwenden die offizielle VPNService-API (Android 4.0+) und erfordern keine Rootrechte und OpenVPN-Settings, das Rootrechte benötigt. &lt; p &gt; OpenVPN für Android ist ein von Arne Schwabe entwickelter Open-Source-Client. Es richtet sich an fortgeschrittene Benutzer und bietet viele erweiterete Einstellungen sowie die Möglichkeit, Profile aus Dateien zu importieren und das konfigurieren und ändern von Profilen innerhalb der App. Der Client basiert auf der Community-Version von OpenVPN 2.x und kann als semioffizieller Client der community angesehen werden. &lt;p&gt; OpenVPN Connect ist ein Closed-Source-Client, der von OpenVPN Technologies, Inc. entwickelt wird. Der Client ist für die normale Verwendung und auf den durchschnittlichen Benutzer ausgerichtet werden und ermöglicht den Import von OpenVPN-Profilen ohne diese innerhalb der App ändern zu können. Dieser Client basiert auf der OpenVPN C++ Neuimplementierung des OpenVPN-Protokolls (Diese war erforderlich, damit OpenVPN Technologies, Inc, eine iOS-app von OpenVPN veröffentlichen onnte). Dieser Client ist auch der offizielle Client von OpenVPN Technologies, Inc. &lt; p&gt; OpenVPN Settings ist der älteste von den Clients und auch eine Benutzeroberfläche für das Open-Source OpenVPN. Im Gegensatz zu OpenVPN für Android es erfordert es Rootrechte und verwendet nicht die VPNService-API; benötigt aber auch nicht Android 4.0+</string>
+ <string name="faq_androids_clients_title">Unterschiede zwischen Android OpenVPN Apps</string>
+ <string name="ignore_multicast_route">Ignoriere Multicastroute: %s</string>
+ <string name="ab_only_cidr">Android unterstützt nur CIDR Routen. Da Routen, die nicht CIDR sind, fast nie verwendet werden, wird OpenVPN für Android eine /32 Route für nicht konforme Routen verwenden und eine Warnung ausgegeben.</string>
+ <string name="ab_tethering_44">Verbindungsfreigabe (WiFi-Hotspot/Tethering) funktioniert, während ein VPN aktiv ist, nutzt aber NICHT die VPN Verbindung.</string>
+ <string name="ab_kitkat_mss">Frühe KitKat-Version setzen einen falschen MSS-Wert für TCP-Verbindungen (#61948). Versuchen Sie die mssfix-Option zu aktivieren, um dieses Problem zu umgehen.</string>
+ <string name="ab_proxy">Android wird ihre Proxy-Einstellungen für die WLan-Verbindung beibehalten wenn keine DNS-Servereinstellungen vorhanden sind. OpenVPN für Android gibt einen entsprechenden Warnhinweis in der Log-Datei aus.<p> Wenn eine VPN-Verbindung einen DNS-Server vorgibt kann kein Proxy genutzt werden. Es gibt keine API um einen Proxy-Server für eine VPN-Verbindung zu nutzen.</p></string>
+ <string name="ab_lollipop_reinstall">Ihre VPN-Anwendung funktioniert möglicherweise nicht mehr wenn diese erst de- und später neu installiert wird. Für Details siehe #80074</string>
+ <string name="ab_not_route_to_vpn">Die konfigurierte Klient-IP-Adresse und die IP-Adressen in die Netzwerkmaske sind nicht in das VPN geroutet. OpenVPN umgeht diesen Fehler, indem eine Route hinzugefügt wird, die zu der Client-IP-Adresse und deren Netzmaske passt.</string>
+ <string name="ab_secondary_users">VPN funktioniert überhaupt nicht für die Sekundärnutzer.</string>
+ <string name="ab_kitkat_reconnect">Mehrere Benutzer berichten, dass die mobile Verbindung/Mobile Datenverbindung häufig getrennt wird, wenn ein VPN aktiv. Das Verhalten scheint nur einige Anbieter/Mobilgerät-Kombination beeinflussen und bisher konnte weder Ursache noch Lösung für den Bug identifiziert werden.</string>
+ <string name="ab_vpn_reachability_44">Nur Ziele, die ohne VPN erreichbar sind, sind auch mit VPN erreichbar. IPv6 VPNs funktionieren überhaupt nicht.</string>
+ <string name="ab_only_cidr_title">Nicht CIDR konforme Routen</string>
+ <string name="ab_proxy_title">Proxy-Verhalten für VPNs</string>
+ <string name="ab_lollipop_reinstall_title">Neuinstallation von VPN-apps</string>
+ <string name="version_upto">%s und früher</string>
+ <string name="copy_of_profile">Kopie von %s</string>
+ <string name="ab_not_route_to_vpn_title">Route zur der konfigurierten VPN IP Adresse</string>
+ <string name="ab_kitkat_mss_title">Falscher MSS-Wert für VPN-Verbindung</string>
+ <string name="ab_secondary_users_title">Sekundäre Tablet-Nutzer</string>
+ <string name="custom_connection_options_warng">Definieren Sie benutzerdefinierte verbindungsspezifische Optionen. Seien Sie vorsichtig!</string>
+ <string name="custom_connection_options">Benutzerdefinierte Optionen</string>
+ <string name="remove_connection_entry">Verbindung entfernen</string>
</resources>
diff --git a/app/src/main/res/values-es/strings-icsopenvpn.xml b/app/src/main/res/values-es/strings-icsopenvpn.xml
index 4cbb152d..f7ce4bf0 100755
--- a/app/src/main/res/values-es/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-es/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Dirección del servidor:</string>
@@ -142,7 +140,7 @@
<string name="menu_import_short">Importar</string>
<string name="import_content_resolve_error">No se pudo leer el perfil a importar</string>
<string name="error_reading_config_file">Error al leer el archivo de configuración</string>
- <string name="add_profile">Agregar perfil</string>
+ <string name="add_profile">Añadir perfil</string>
<string name="import_could_not_open">No se pudo encontrar el archivo %1$s mencionado en el archivo de configuracion importado</string>
<string name="importing_config">Importando archivo de configuración del origen %1$s</string>
<string name="import_warning_custom_options">Su configuración tiene algunas opciones de configuración que no están establecidas en la interfaz de usuario . Estas opciones fueron agregadas como opciones de configuración personalizadas. A continuación se muestra la configuración personalizada:</string>
@@ -162,7 +160,7 @@
<string name="converted_profile_i">perfil importado %d</string>
<string name="broken_images">Imágenes rotas</string>
<string name="broken_images_faq">&lt;p&gt;Las imágenes oficiales de HTC son conocidas por tener un extraño problema de enrutamiento, causando que el tráfico no fluya a través del túnel (Ver también &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\"&gt;Issue 18&lt;/a&gt; en el bug tracker.)&lt;/p&gt;&lt;p&gt; Han reportado que el VPNService hace falta completamente de las imagenes oficiales de SONY más viejas del XPeria Arc S y Xperia Ray. (Ver también &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\"&gt;Issue 29&lt;/a&gt; en el bug tracker.)&lt;/p&gt;&lt;p&gt;Puede faltar el módulo tun o los permisos de /dev/tun/ pueden estar incorrectos. Algunas imágenes de CM9 necesitan habilitada la opcion \"Fix ownership\" option bajo \"Hacks específicos del dispositivo\".&lt;/p&gt;&lt;p&gt;De mayor importancia: Si tu dispositivo tiene una imágen corrupta de Android, reportalo a tu proveedor. Entre mayor gente reporte el problema al proveedor, mayores son las probabilidades de que lo reparen.&lt;/p&gt;</string>
- <string name="pkcs12_file_encryption_key">Clave PKCS12 de cifrado de archivos</string>
+ <string name="pkcs12_file_encryption_key">Clave de cifrado del fichero PKCS12</string>
<string name="private_key_password">Contraseña de clave privada</string>
<string name="password">Contraseña</string>
<string name="file_icon">icono de archivo</string>
@@ -187,7 +185,7 @@ hacia/de Móvil)</string>
<string name="error_rsa_sign">Error al firmar con la llave del almacén de llaves de Android %1$s: %2$s</string>
<string name="faq_system_dialogs">El aviso de conectividad VPN que esta aplicación puede interceptar todo el trafico esta impuesta por el sistema para evitar abusos de la API VPNService.\nLa notificación de conectividad (El símbolo de llave) también esta impuesta por el sistema Android para notificar una conexión VPN en curso. En algunas imágenes, esta notificación también emite un sonido.\nAndroid ha introducido estos diálogos de sistema para su seguridad e se ha asegurado que no pueden ser evitados. (En algunas imágenes, esto incluye la notificación sonora)</string>
<string name="faq_system_dialogs_title">Advertencia de conexión y sonido de notificación</string>
- <string name="translationby">Traducción al español por José Luis Bandala Pérez&lt;luis.449bp@gmail.com&gt;</string>
+ <string name="translationby">Traducción al español por José Luis Bandala Pérez&lt;luis449bp+openvpn@gmail.com&gt;</string>
<string name="ipdns">IP y DNS</string>
<string name="basic">Básico</string>
<string name="routing">Enrutamiento</string>
@@ -205,7 +203,7 @@ hacia/de Móvil)</string>
<string name="getproxy_error">Error al obtener la configuración de proxy: %s</string>
<string name="using_proxy">Usando proxy %1$s %2$d</string>
<string name="use_system_proxy">Usar el proxy del sistema</string>
- <string name="use_system_proxy_summary">Utilice la configuración del sistema para los proxies HTTP/HTTPS a conectar.</string>
+ <string name="use_system_proxy_summary">Utilice la configuración del sistema para los proxies HTTP/HTTPS al conectar.</string>
<string name="donatewithpaypal">Usted puede &lt;a href=\"https://www.paypal.com/cgi-bin/webscr?hosted_button_id=R2M6ZP9AF25LS&amp;amp;cmd=_s-xclick\"&gt;donar con PayPal&lt;/a&gt; </string>
<string name="onbootrestartsummary">OpenVPN volvera a conectar a una VPN si estaba activa en el apagado/reinicio del sistema. Por favor lea la P+F de advertencia de conexión antes de usar esta opción.</string>
<string name="onbootrestart">Vuelva a conectar al reiniciar</string>
@@ -219,8 +217,8 @@ hacia/de Móvil)</string>
<string name="no_vpn_profiles_defined">No hay perfiles VPN definidos.</string>
<string name="add_new_vpn_hint">Use el icono &lt;img src=\"ic_menu_add\"/&gt; para agregar una nueva VPN</string>
<string name="vpn_import_hint">Use el icono &lt;img src=\"ic_menu_archive\"/&gt; para importar un perfil existente (.ovpn or .conf) de tu tarjeta.</string>
- <string name="faq_hint">Asegúrese de checar también las preguntas frecuentes. Hay una guía de inicio rápido.</string>
- <string name="faq_routing_title">Configuración de enrutamiento o interfaz</string>
+ <string name="faq_hint">Asegúrese de revisar también las preguntas frecuentes. Hay una guía de inicio rápido.</string>
+ <string name="faq_routing_title">Configuración de enrutamiento/interfaz</string>
<string name="faq_routing">El enrutamiento y la configuración de la interfaz no se realiza a través de comandos tradicionales ifconfig / ruta, pero mediante el uso de la API VPNService. Esto resulta en una configuración de enrutamiento diferente que en otros sistemas operativos. La configuración del túnel VPN consta de la dirección IP y las redes que deben ser colocados de través de esta interfaz. Se necesita Especialmente hay dirección compañero de estudios o de gateway. Rutas especiales para llegar a la VPN Server (por ejemplo agregan al usar redirect-gateway) no son necesarios, ya sea. La aplicación, en consecuencia ignorará esta configuración al importar una configuración. La aplicación asegura con la API VPNService que la conexión con el servidor no se encamina a través del túnel VPN. Sólo redes especificando ser enrutados a través del túnel es compatible. La aplicación intenta detectar las redes que no deben ser enrutados a través de túnel (por ejemplo, la ruta xxxx aaaa net_gateway) y calcula un conjunto de rutas que excluye este rutas para emular el comportamiento de otras plataformas. Las ventanas de registro muestra la configuración de la VPNService al establecer una conexión.</string>
<string name="persisttun_summary">No regresar a modo sin conexión VPN cuando OpenVPN esta volviendose a conectar.</string>
<string name="persistent_tun_title">Tun persistente</string>
@@ -291,7 +289,7 @@ hacia/de Móvil)</string>
<string name="pauseVPN">Pausar VPN</string>
<string name="resumevpn">Reanudar VPN</string>
<string name="state_userpause">VPN pausado por solicitud del usuario</string>
- <string name="state_screenoff">VPN pausado - pantalla fuera</string>
+ <string name="state_screenoff">VPN pausado - pantalla apagada</string>
<string name="device_specific">Hacks específicos del Dispositivo</string>
<string name="cannotparsecert">No se puede mostrar la información del certificado</string>
<string name="appbehaviour">Comportamiento de la aplicación</string>
@@ -352,4 +350,29 @@ hacia/de Móvil)</string>
<string name="no_remote_defined">Servidor remoto no definido</string>
<string name="duplicate_vpn">Duplicar perfil VPN</string>
<string name="duplicate_profile_title">Duplicando Perfil: %s</string>
+ <string name="show_log">Mostrar registro</string>
+ <string name="faq_android_clients">Existen múltiples clientes OpenVPN para Android. Los más comunes son OpenVPN para Android (este cliente), OpenVPN Connect y Configuración de OpenVPN&lt;p&gt;Los clientes se pueden agrupar en dos grupos:. OpenVPN para Android y OpenVPN Conectar utilizar la API VPNService oficial (Android 4.0+) y requieren ninguna raíz y Configuración de OpenVPN que utiliza la raíz.&lt;p&gt;OpenVPN para Android es un cliente de código abierto y desarrollado por Arne Schwabe. Está dirigido a los usuarios más avanzados y ofrece muchas opciones y la posibilidad de importar los perfiles de los archivos y configurar perfiles / cambio dentro de la aplicación. El cliente se basa en la versión de la comunidad de OpenVPN. Se basa en el código fuente 2.x OpenVPN. Este cliente puede ser visto como el semi oficialmente cliente de la comunidad.&lt;p&gt;OpenVPN Connect es cliente de código abierto no que es desarrollado por OpenVPN Technologies, Inc. El cliente tiene sangría para ser cliente de uso general y moree dirigido al usuario medio y permite la importación de perfiles de OpenVPN. Este cliente se basa en la reimplementación OpenVPN C ++ del protocolo OpenVPN (Esto fue necesario para permitir Tecnologías OpenVPN, Inc para publicar una aplicación para iOS OpenVPN). Este cliente es el cliente oficial de las tecnologías deO penVPN&lt;p&gt; OpenVPN Ajustes es el más antiguo de los clientes y también una interfaz de usuario para el software libre OpenVPN. En contraste con OpenVPN para Android requiere raíz y no utiliza el API VPNService. No depende de Android 4.0+</string>
+ <string name="faq_androids_clients_title">Differences between the OpenVPN Android clients</string>
+ <string name="ignore_multicast_route">Haciendo caso omiso de ruta multidifusión: %s</string>
+ <string name="ab_only_cidr">Android sólo admite rutas CIDR a la VPN. Desde rutas no CIDR casi nunca se usan, OpenVPN para Android utilizará un / 32 para las rutas que no son CIDR y emitir una advertencia.</string>
+ <string name="ab_tethering_44">Tethering funciona mientras que el VPN está activa. La conexión atada no utilizará el VPN.</string>
+ <string name="ab_kitkat_mss">Primera versión KitKat establece el valor incorrecto MSS sobre conexiones TCP (# 61948). OpenVPN para automáticamente permitirá mssfix opción para solucionar este error.</string>
+ <string name="ab_proxy">Android seguirá utilizando la configuración del proxy especificados para la conexión / Wi-Fi móvil cuando no están definidos los servidores DNS. OpenVPN para Android le advertirá sobre esto en el registro.<p>Cuando una VPN establece un servidor DNS Android no lo hará un proxy. No hay ninguna API para configurar un proxy para una conexión VPN.</p></string>
+ <string name="ab_lollipop_reinstall">Aplicaciones VPN pueden dejar de funcionar cuando desinstalado y reinstalado de nuevo. Para más detalles ver # 80074</string>
+ <string name="ab_not_route_to_vpn">La IP del cliente configurado y las IPs en su máscara de red no se enrutan a la VPN. OpenVPN soluciona este error al agregar explícitamente una ruta que corrosponds a la IP del cliente y su máscara de red</string>
+ <string name="ab_persist_tun">La apertura de un dispositivo tun mientras que otro dispositivo tun está activo, que se utiliza para el apoyo tun-persistir, bloquea los VPNServices en el dispositivo. Es necesario reiniciar para que el trabajo VPN de nuevo. OpenVPN para Android intenta evitar reabrir el dispositivo tun y si realmente se necesita primero cierra el TUN actual antes de abrir el nuevo dispositivo TUN para evitar estrellarse. Esto puede conducir a una corta ventana donde los paquetes se envían a través de la conexión no VPN. Incluso con esta solución los VPNServices a veces se bloquea y requiere un reinicio del dispositivo.</string>
+ <string name="ab_secondary_users">VPN no funciona en absoluto para los usuarios secundarios.</string>
+ <string name="ab_kitkat_reconnect">"Varios usuarios reportan que la conexión móvil / conexión de datos móviles se cae con frecuencia durante el uso de la aplicación VPN. El comportamiento parece afectar sólo alguna combinación móvil proveedor / dispositivo y hasta ahora ninguna causa / solución para el bug se pudo identificar."</string>
+ <string name="ab_vpn_reachability_44">Sólo destino puede llegar a través de la VPN que se puede llegar sin VPN. IPv6 VPNs no funciona en absoluto.</string>
+ <string name="ab_only_cidr_title">Rutas no CIDR</string>
+ <string name="ab_proxy_title">Comportamiento Proxy para VPN</string>
+ <string name="ab_lollipop_reinstall_title">Reinstalación de aplicaciones VPN</string>
+ <string name="version_upto">%s y anteriores</string>
+ <string name="copy_of_profile">copia de %s</string>
+ <string name="ab_not_route_to_vpn_title">Ruta a la dirección IP configurada</string>
+ <string name="ab_kitkat_mss_title">Valor MSS incorrecto para la conexión VPN</string>
+ <string name="ab_secondary_users_title">Los usuarios de tabletas secundarias</string>
+ <string name="custom_connection_options_warng">Especifique las opciones específicas de conexión personalizada. Úselo con cuidado</string>
+ <string name="custom_connection_options">Opciones personalizadas</string>
+ <string name="remove_connection_entry">Eliminar entrada de conexión</string>
</resources>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ec8c21ff..7f0670b8 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,11 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <string name="info">información</string>
- <string name="show_connection_details">Mostrar detalles de la conexión</string>
- <string name="routes_info">Rutas: %s</string>
- <string name="routes_info6">Rutas IPv6: %s</string>
- <string name="error_empty_username">El nombre de usuario no debe estar vacío.</string>
- <string name="cert_from_keystore">Conseguido el certificado de \'%s\' de almacén de claves</string>
- <string name="repository_url_text">Código fuente disponible en https://github.com/leapcode/bitmask_android/</string>
- <string name="leap_tracker">Tracker disponible en https://leap.se/code</string>
+
+
+ <string name="retry">Reintentar</string>
+ <string name="translation_project_text">Traducciones son bienvenidas. Puedes ir a nuestra página de Transifex: https://www.transifex.com/projects/p/bitmask-android/</string>
+ <string name="switch_provider_menu_option">Cambiar de proveedor</string>
+ <string name="info">información</string>
+ <string name="show_connection_details">Mostrar detalles de la conexión</string>
+ <string name="routes_info">Rutas: %s</string>
+ <string name="routes_info6">Rutas IPv6: %s</string>
+ <string name="error_empty_username">El usuario no puede estar vacío.</string>
+ <string name="cert_from_keystore">Certificado de \'%s\' obtenido de almacén de claves</string>
+ <string name="repository_url_text">Código fuente disponible en https://github.com/leapcode/bitmask_android/</string>
+ <string name="leap_tracker">Tracker disponible en https://leap.se/code</string>
+ <string name="title_activity_dashboard">Bitmask</string>
+ <string name="provider_label">Proveedor:</string>
+ <string name="provider_label_none">Ningún proveedor configurado</string>
+ <string name="status_unknown">Estado no definido.</string>
+ <string name="eip_service_label">Acceso a Internet Encriptado con VPN</string>
+ <string name="configuration_wizard_title">Elige un proveedor</string>
+ <string name="new_provider_button">Nuevo proveedor</string>
+ <string name="introduce_new_provider">Añadir un nuevo proveedor</string>
+ <string name="save">Guardar</string>
+ <string name="new_provider_uri">Dominio</string>
+ <string name="valid_url_entered">El dominio está bien formado</string>
+ <string name="not_valid_url_entered">Dominio no válido</string>
+ <string name="provider_details_fragment_title">Detalles del proveedor</string>
+ <string name="use_anonymously_button">Utilizar sin registrarse</string>
+ <string name="username_hint">usuario</string>
+ <string name="username_ask">Por favor, introduce tu usuario</string>
+ <string name="password_hint">contraseña</string>
+ <string name="user_message">Mensaje al usuario</string>
+ <string name="title_about_activity">Acerca de Bitmask"</string>
+ <string name="error_srp_math_error_user_message">Inténtalo de nuevo: error en el servidor.</string>
+ <string name="error_bad_user_password_user_message">Usuario o contraseña incorrectos.</string>
+ <string name="error_not_valid_password_user_message">Al menos 8 caracteres.</string>
+ <string name="error_client_http_user_message">Inténtalo de nuevo: error en el cliente HTTP</string>
+ <string name="error_io_exception_user_message">Inténtalo de nuevo: error de E/S</string>
+ <string name="error_json_exception_user_message">Inténtalo de nuevo: respuesta mal formada del servidor</string>
+ <string name="error_no_such_algorithm_exception_user_message">Actualiza Bitmask</string>
+ <string name="signup_or_login_button">Registrarse/Iniciar sesión</string>
+ <string name="login_button">Iniciar sesión</string>
+ <string name="logout_button">Cerrar sesión</string>
+ <string name="signup_button">Registrarse</string>
+ <string name="setup_error_title">Error de configuración</string>
+ <string name="setup_error_configure_button">Configurar</string>
+ <string name="setup_error_close_button">Salir</string>
+ <string name="setup_error_text">Sucedió un error configurando Bitmask con tu proveedor elegido.\n\nPuedes volver a intentarlo, o elegir otro proveedor.</string>
+ <string name="server_unreachable_message">No se ha detectado red para hablar con el servidor, inténtalo de nuevo.</string>
+ <string name="error.security.pinnedcertificate">Error de seguridad, actualiza la aplicación o elige otro proveedor.</string>
+ <string name="malformed_url">No parece que sea un proveedor de Bitmask.</string>
+ <string name="certificate_error">No es un proveedor de Bitmak de confianza.</string>
+ <string name="service_is_down_error">El servicio está caído.</string>
+ <string name="configuring_provider">Configurando el proveedor</string>
+ <string name="incorrectly_downloaded_certificate_message">Tu certificado VPN no pudo ser descargado. Intenta iniciar sesión si es posible.</string>
+ <string name="downloading_certificate_message">Descargando certificado VPN</string>
+ <string name="updating_certificate_message">Actualizando certificado VPN</string>
+ <string name="log_out_failed_message">No pudo cerrarse la sesión. Inténtalo más tarde, quizás sea un problema de la red o del proveedor. Si el problema persiste, borra los datos locales de Bitmask desde la configuración de Android.</string>
+ <string name="login.riseup.warning">"Usuarios de Riseup: es necesario crear una cuenta aparte para utilizar el servicio de VPN."</string>
+ <string name="succesful_authentication_message">Sesión iniciada.</string>
+ <string name="authentication_failed_message">Inicio de sesión fallido.</string>
+ <string name="registration_failed_message">Falló el registro de un nuevo usuario.</string>
+ <string name="eip_status_start_pending">Iniciando la conexión</string>
+ <string name="eip_cancel_connect_title">¿Abortar conexión?</string>
+ <string name="eip_cancel_connect_text">Hay una conexión iniciándose. ¿Quieres cancelarla?</string>
+ <string name="eip.warning.browser_inconsistency">Para salvaguardar la privacidad de tu información personal, te recomendamos que después de apagar la VPN cierres la sesión del navegador y abras una sesión privada en él. Gracias.</string>
+ <string name="eip_state_not_connected">"¡Conexión no protegida!"</string>
+ <string name="eip_state_connected">Conexión protegida.</string>
+ <string name="provider_problem">Parece que hay un problema con el proveedor.</string>
+ <string name="try_another_provider">Prueba con otro proveedor, o contacta con este.</string>
+ <string name="default_username">Anónimo</string>
+ <string name="logged_in_user_status">inició sesión.</string>
+ <string name="logged_out_user_status">cerró la sesión.</string>
+ <string name="didnt_log_out_user_status">no cerró la sesión.</string>
+ <string name="not_logged_in_user_status">no ha iniciado sesión.</string>
+ <string name="logging_in_user_status">está iniciando sesión.</string>
+ <string name="logging_out_user_status">está cerrando sesión.</string>
+ <string name="signingup_message">está siendo registrado.</string>
+ <string name="vpn.button.turn.on">Iniciar</string>
+ <string name="vpn.button.turn.off">Apagar</string>
</resources>
diff --git a/app/src/main/res/values-et/strings-icsopenvpn.xml b/app/src/main/res/values-et/strings-icsopenvpn.xml
index c5174284..a132ed7a 100755
--- a/app/src/main/res/values-et/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-et/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Serveri aadress:</string>
@@ -351,4 +349,29 @@
<string name="no_remote_defined">Kaugserverid määramata</string>
<string name="duplicate_vpn">Dubleeritud VPN profiil</string>
<string name="duplicate_profile_title">Duplitseeritakse profiili: %s</string>
+ <string name="show_log">Näita logi</string>
+ <string name="faq_android_clients">Androidile leidub mitmeid OpenVPN kliente. Enimlevinud on OpenVPN for Android (käesolev klient), OpenVPN Connect ja OpenVPN Settings.&lt;p&gt;Kliente võib tinglikulkt jagada kahte rühma: OpenVPN for Android ja OpenVPN Connect kasutavad ametlikku VPNService API\'t (Android 4.0+) mis ei nõua ruutimist ning OpenVPN Settings mis kasutab ruutimist.&lt;p&gt;OpenVPN for Android on Arne Schwabe poolt arendatav vabavaraline klient. See on suunatud kogenumatele kasutajatele, pakkudes hulgaliselt valikuid ning programmisisese profiilide failidest importimise ja hilisema profiilide seadistamise/muutmise võimaluse. Klient põhineb OpenVPN vabavarakogukonna versioonil mille aluseks on OpenVPN 2.x lähtetekst. Seda klienti võib vaadelda kui poolametlikku vabavarakogukonna klienti. &lt;p&gt;OpenVPN Connect on mittevabavaraline klient mida arendab OpenVPN Technologies, Inc. See klient on mõeldud üldiseks kasutamiseks ja suunatud keskmisele kasutajale, lubades OpenVPN profiilide importimist. Klient baseerub OpenVPN C++ uuestiteostatud OpenVPN protokolllil (Tegu oli sundkäiguga mis võimaldas OpenVPN Technologies, Inc. avaldada iOS versiooni OpenVPN programmist). See klient on ametlik OpenVPN Technologies klient&lt;p&gt; OpenVPN Settings on vanim mainitud kolmest ning samuti vabavaralise OpenVPN kasutajaliides. Erinevalt programmist OpenVPN for Android nõuab selle kasutamine rootimist ja ei kasuta VPNService API\'t. Seepärast töötab see ka vanematel versioonidel kui Android 4.0+</string>
+ <string name="faq_androids_clients_title">OpenVPN Androidi klientrakenduste erinevused</string>
+ <string name="ignore_multicast_route">Eiran multicast marsruuti: %s</string>
+ <string name="ab_only_cidr">Android toetab VPN jaoks ainult CIDR marsruute. Kuna mitte-CIDR marsruute ei kasutata peaaegu kunagi, siis kasutab OpenVPN for Android marsruutidele mis ei ole CIDR, maski /32 ja väljastab hoiatuse.</string>
+ <string name="ab_tethering_44">Lõastamine (tethering) töötab ka aktiivse VPN puhul. Lõastatud ühendus EI kasuta VPN kanalit.</string>
+ <string name="ab_kitkat_mss">Varased KitKat versioonid kasutavad TCP ühendustel vale MSS väärtust (#61948). OpenVPN määrab vastuabinõuna automaatselt mssfix valiku.</string>
+ <string name="ab_proxy">Kui ühtegi DNS serverit pole määratud, siis jätkab Android mobiilsele/Wi-Fi ühendusele määratud puhverserveri kasutamist. OpenVPN for Android hoiatab sellest logis.<p>Kui VPN seadistab DNS serveri siis Android ei puhverda. VPN puhverserveri määramiseks puudub API.</p></string>
+ <string name="ab_lollipop_reinstall">VPN apid ei pruugi enam töötada pärast eemaldamist ja uuestipaigaldamist. Täpsem info #80074</string>
+ <string name="ab_not_route_to_vpn">Seadistatud kliendi IP ja selle võrgumaskis sisalduvaid IP-sid ei marsruudita VPN kaudu. OpenVPN lahendab selle probleemi lisades marsruudi kliendi IP ja võrgumaski jaoks</string>
+ <string name="ab_persist_tun">Tun seadme avamine samal ajal kui mõni teine tun seade on aktiivne, mida kasutatakse püsiva-tun tagamiseks, jooksutab seadme VPN teenused kokku. VPN kasutamiseks tuleb seade uuesti käivitada. OpenVPN üritab vältida tun seadme uuestiavamist ja tõsise vajaduse korral sulgeb uue TUN avamisel eelnevalt aktiivse TUN seadme et vältida hangumist. See võib põhjustada lühiajalise akna mille jooksul saadetakse pakette VPN ühendusest mööda. Kuid isegi vaatamata kirjeldatud protsessile võib VPN teenus vahest kokku joosta ja seade vajada uuestikäivitamist.</string>
+ <string name="ab_secondary_users">VPN töötab ainult põhikasutaja jaoks.</string>
+ <string name="ab_kitkat_reconnect">"Mitmed kasutajad on teatanud et mobiilses ühenduses/mobiilses andmesides esineb VPN programmi kasutamisel sagedasi katkestusi. Selline käitumine näib esinevat ainult teatud teenusepakkuja/seadme kombinatsioonide puhul ja seni ei ole põhjust/leevendust leitud. "</string>
+ <string name="ab_vpn_reachability_44">Üle VPN on ligipääsetav ainult aadress, mis on kättesaadav ka ilma VPN ühenduseta. IPv6 VPNid ei tööta üldse.</string>
+ <string name="ab_only_cidr_title">Mitte-CIDR marsruudid</string>
+ <string name="ab_proxy_title">Puhverserveri käitumine VPN puhul</string>
+ <string name="ab_lollipop_reinstall_title">VPN appide uuestipaigaldamine</string>
+ <string name="version_upto">%s ja eelnevad</string>
+ <string name="copy_of_profile">%s koopia</string>
+ <string name="ab_not_route_to_vpn_title">Seadistatud IP aadressi marsruut</string>
+ <string name="ab_kitkat_mss_title">VPN ühenduse vale MSS väärtus</string>
+ <string name="ab_secondary_users_title">Teisesed tahvli kasutajad</string>
+ <string name="custom_connection_options_warng">Seadista kohandatavad ühendusespetsiifilised valikud. Kasuta ettevaatlikult</string>
+ <string name="custom_connection_options">Kohandatavad valikud</string>
+ <string name="remove_connection_entry">Eemalda ühenduse kirje</string>
</resources>
diff --git a/app/src/main/res/values-fr/strings-icsopenvpn.xml b/app/src/main/res/values-fr/strings-icsopenvpn.xml
index 657646c8..d5ab917c 100755
--- a/app/src/main/res/values-fr/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-fr/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">"Adresse du serveur:"</string>
@@ -221,6 +219,7 @@ Sur certaines images, cette notification joue un son.\nAndroid à introduit ces
<string name="vpn_import_hint">"Utilisez l\'icône &lt;img src=\"ic_menu_archive\"/&gt; pour importer un fichier profil (.opvpn ou .conf) de votre carte SD."</string>
<string name="faq_hint">"Veillez également à consulter la FAQ. Il s\'y trouve un guide de démarrage rapide."</string>
<string name="faq_routing_title">"Redirections / Configuration de l\'interface"</string>
+ <string name="faq_routing">La configuration du routage et des interfaces n\'est pas faite par l\'intermédiaire des commandes traditionnelles ifconfig/route, mais en utilisant l\'API VPNService. Il en résulte une configuration de routage différente que sur les autres systèmes d\'exploitation. \nLa configuration du tunnel VPN se compose de l\'adresse IP et des réseaux qui doivent être routés via cette interface. En particulier aucune adresse de pair ou de passerelle n\'est nécessaire ou requise. Des routes spéciales pour atteindre le serveur VPN (par exemple ajoutées lorsque vous utilisez \"redirect-gateway\") ne sont pas nécessaires. L\'application ignore par conséquent ces paramètres lors de l\'importation d\'une configuration. L\'application assure avec l\'API VPNService que la connexion au serveur ne passe pas par le tunnel VPN.\nL\'API VPNService ne permet pas de spécifier les réseaux qui ne doivent pas être routés via le VPN. Pour contourner ce problème, l\'application essaye de détecter les réseaux qui ne doivent pas être routés par le tunnel (ex. route x.x.x.x y.y.y.y net_gateway) et calcule un ensemble de routes qui exclut cette route pour mimer le comportement des autres plates-formes. La fenêtre des logs montre la configuration de VPNService lors d\'une connexion.\nEn coulisse: Android 4.4+ n\'utilise pas la politique du routage. Utiliser route/ifconfig n\'affichera pas les routes installés. Utilisez plutôt ip rule, iptables -t mangle -L</string>
<string name="persisttun_summary">Ne pas couper la connexion VPN lors de la reconnexion d\'OpenVPN.</string>
<string name="persistent_tun_title">Persistance de l\'interface TUN</string>
<string name="openvpn_log">Log OpenVPN</string>
@@ -318,10 +317,37 @@ Sur certaines images, cette notification joue un son.\nAndroid à introduit ces
<string name="faq_system_dialog_xposed">Si vous avez \"rooté\" votre Android vous pouvez installer &lt;a href=\"http://xposed.info/\"&gt;Xposed framework&lt;/a&gt; et &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;le module de confirmation VPN&lt;/a&gt; à vos risques et périls\"</string>
<string name="full_licenses">Licences complètes</string>
<string name="blocklocal_summary">Les réseaux directement connectés aux interfaces locales ne seront pas routés via le VPN. Décochez cette option pour rediriger tout le trafic local vers le VPN.</string>
- <string name="blocklocal_title">Ne pas utilisé le VPN pour les réseaux locaux</string>
+ <string name="blocklocal_title">Ne pas utiliser le VPN pour les réseaux locaux</string>
<string name="userpw_file">Fichier Nom d\'utilisateur/Mot de passe</string>
<string name="imported_from_file">[Importé de : %s]</string>
<string name="files_missing_hint">Certains fichiers sont introuvables. Sélectionner les fichiers pour importer le profil :</string>
<string name="openvpn_is_no_free_vpn">Pour utiliser cette application, vous avez besoin d\'un fournisseur/passerelle VPN qui soutient OpenVPN (souvent fourni par votre employeur). Vérifier ici http://community.openvpn.net/ pour plus d\'informations sur OpenVPN et comment configurer votre propre serveur OpenVPN.</string>
<string name="import_log">Journal d\'importation :</string>
+ <string name="ip_looks_like_subnet">Topologie VPN «%3$s » spécifiée mais ifconfig %1$s %2$s ressemble plus à une adresse IP avec un masque de réseau. On suppose que la topologie « sous-réseau » est utilisée.</string>
+ <string name="mssfix_invalid_value">La valeur de mssfix doit être un entier compris entre 0 et 9000</string>
+ <string name="mssfix_value_dialog">Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed this number of bytes. (default is 1450)</string>
+ <string name="mssfix_checkbox">Override MSS value of TCP payload</string>
+ <string name="mssfix_dialogtitle">Set MSS of TCP payload</string>
+ <string name="client_behaviour">Comportement du client</string>
+ <string name="clear_external_apps">Clear allowed external apps</string>
+ <string name="loading">Chargement&#8230;</string>
+ <string name="allowed_vpn_apps_info">Allowed VPN apps: %1$s</string>
+ <string name="disallowed_vpn_apps_info">Disallowed VPN apps: %1$s</string>
+ <string name="app_no_longer_exists">Package %s is no longer installed, removing it from app allow/disallow list</string>
+ <string name="vpn_disallow_radio">VPN is used for all apps but exclude selected</string>
+ <string name="vpn_allow_radio">VPN is used for only for selected apps</string>
+ <string name="query_delete_remote">Remove remote server entry?</string>
+ <string name="keep">Garder</string>
+ <string name="delete">Supprimer</string>
+ <string name="add_remote">Add new remote</string>
+ <string name="remote_random">Use connection entries in random order on connect</string>
+ <string name="remote_no_server_selected">You need to define and enable at least one remote server.</string>
+ <string name="server_list">Liste des serveurs</string>
+ <string name="vpn_allowed_apps">Allowed Apps</string>
+ <string name="advanced_settings">Paramètres avancés</string>
+ <string name="payload_options">Payload options</string>
+ <string name="tls_settings">Paramètres TLS</string>
+ <string name="no_remote_defined">No remote defined</string>
+ <string name="duplicate_vpn">Dupliquer le profil VPN</string>
+ <string name="duplicate_profile_title">Duplicating profile: %s</string>
</resources>
diff --git a/app/src/main/res/values-hu/strings-icsopenvpn.xml b/app/src/main/res/values-hu/strings-icsopenvpn.xml
index 2efdcf5f..5be8bbc4 100755
--- a/app/src/main/res/values-hu/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-hu/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Szerver cím:</string>
diff --git a/app/src/main/res/values-in/strings-icsopenvpn.xml b/app/src/main/res/values-in/strings-icsopenvpn.xml
index 3dac7c71..07331433 100755
--- a/app/src/main/res/values-in/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-in/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Alamat Server:</string>
@@ -89,6 +87,7 @@
<string name="default_route_summary">Alihkan semua lalulintas data melalui VPN</string>
<string name="use_default_title">Gunakan rute standar</string>
<string name="custom_route_message">Masukkan rute butan sendiri. Masukkan tujuan dalam format CIDR. \"10.0.0.0/8 2002:: / 16\" akan mengarahkan jaringan 10.0.0.0/8 dan 2002:: / 16 melalui jaringan VPN</string>
+ <string name="custom_route_message_excluded">Routes that should NOT be routed over the VPN. Use the same syntax as for included routes.</string>
<string name="custom_routes_title">Rute buatan sendiri</string>
<string name="custom_routes_title_excluded">Jaringan Dikecualikan</string>
<string name="log_verbosity_level">Tingkat rincian catatan</string>
@@ -104,6 +103,7 @@
<string name="last_openvpn_tun_config">Membuka interface tun :</string>
<string name="local_ip_info">IPv4 lokal : %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
<string name="dns_server_info">DNS Server: %1$s, Domain: %2$s</string>
+ <string name="routes_info_incl">Rute: %1$s %2$s</string>
<string name="ip_not_cidr">Memilki informasi antarmuka %1$s dan %2$s, asumsi alamat kedua adalah alamat remote. Menggunakan netmask /32 untuk IP lokal. Mode yang diberikan oleh OpenVPN adalah \"%3$s\".</string>
<string name="route_not_cidr">Tidak masuk akal membuat %1$s dan %2$s sebagai rute IP dengan netmask CIDR, Gunakan /32 sebagai netmask.</string>
<string name="route_not_netip">rute yang diperbaiki %1$s/%2$s hingga %3$s/%2$s</string>
diff --git a/app/src/main/res/values-it/strings-icsopenvpn.xml b/app/src/main/res/values-it/strings-icsopenvpn.xml
index 36198678..f35a4b66 100755
--- a/app/src/main/res/values-it/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-it/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Indirizzo server:</string>
@@ -326,16 +324,28 @@ Effettuata la lettura del file di configurazione</string>
<string name="files_missing_hint">Alcuni file non possono essere trovati. Si prega di selezionare i file da importare nel profilo:</string>
<string name="openvpn_is_no_free_vpn">Per utilizzare questa applicazione è necessario un provider VPN/gateway VPN che supportino OpenVPN (spesso forniti dal datore di lavoro). Vai a http://community.openvpn.net/ per ulteriori informazioni su OpenVPN e come configurare il proprio server OpenVPN.</string>
<string name="import_log">Registro importazione:</string>
+ <string name="mssfix_invalid_value">Il valore di fix MSS deve essere un intero tra 0 e 9000</string>
<string name="mssfix_checkbox">Sovrascrivi il valore del MSS nel payload TCP</string>
<string name="mssfix_dialogtitle">Setta il valore del MSS nel payload TCP</string>
<string name="client_behaviour">Comportamento Client</string>
+ <string name="clear_external_apps">Svuota la lista delle applicazioni consentite</string>
<string name="loading">Caricando&#8230;</string>
+ <string name="allowed_vpn_apps_info">Applicazioni VPN consentite: %1$s</string>
+ <string name="disallowed_vpn_apps_info">Applicazioni VPN non consentite: %1$s</string>
+ <string name="app_no_longer_exists">Il package (applicazione) %s non è più installato, verrà rimosso dalla lista delle app consentite/non consentite</string>
+ <string name="vpn_disallow_radio">La VPN è utilizzata per tutte le app eccetto quelle selezionate</string>
+ <string name="vpn_allow_radio">La VPN è utilizzata solo per le app selezionate</string>
+ <string name="query_delete_remote">Rimuovere la voce di server remoto?</string>
<string name="keep">Mantieni</string>
<string name="delete">Elimina</string>
+ <string name="add_remote">Aggiungi nuovo server</string>
<string name="server_list">Lista Server</string>
+ <string name="vpn_allowed_apps">Applicazioni consentite</string>
<string name="advanced_settings">Impostazioni Avanzate</string>
<string name="payload_options">Opzioni Payload</string>
<string name="tls_settings">Impostazioni TLS</string>
<string name="duplicate_vpn">Profilo VPN duplicato</string>
<string name="duplicate_profile_title">Duplicazione del profilo: %s</string>
+ <string name="version_upto">%s e precedenti</string>
+ <string name="copy_of_profile">Copia di %s</string>
</resources>
diff --git a/app/src/main/res/values-ja/strings-icsopenvpn.xml b/app/src/main/res/values-ja/strings-icsopenvpn.xml
index 792e6200..f12d149b 100755
--- a/app/src/main/res/values-ja/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ja/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">サーバアドレス</string>
diff --git a/app/src/main/res/values-ko/strings-icsopenvpn.xml b/app/src/main/res/values-ko/strings-icsopenvpn.xml
index 9266a36c..4a4273d8 100755
--- a/app/src/main/res/values-ko/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ko/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">서버 주소:</string>
@@ -89,7 +87,9 @@
<string name="default_route_summary">VPN을 통해 모든 트래픽을 보냅니다.</string>
<string name="use_default_title">기본 라우트 사용하기</string>
<string name="custom_route_message">사용자 지정 라우트를 입력하십시오. 목적지는 CIDR 형식으로만 입력하십시오. \"10.0.0.0/8 2002::/16\"은 10.0.0.0/8 과 2002::/16 네트워크를 VPN으로 보냅니다.</string>
+ <string name="custom_route_message_excluded">VPN을 통해 라우팅하지 말아 경로. 포함 경로와 동일한 구문을 사용합니다.</string>
<string name="custom_routes_title">사용자 지정 라우트</string>
+ <string name="custom_routes_title_excluded">123456</string>
<string name="log_verbosity_level">로그의 자세한 정도</string>
<string name="float_summary">인증된 패킷은 IP와 상관없이 허용</string>
<string name="float_title">플로팅 서버 허용</string>
diff --git a/app/src/main/res/values-nl/strings-icsopenvpn.xml b/app/src/main/res/values-nl/strings-icsopenvpn.xml
index b486706e..2b3468e3 100755
--- a/app/src/main/res/values-nl/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-nl/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Server Adres:</string>
@@ -87,15 +85,24 @@
<string name="ignore_routes_summary">Negeer routes ontvangen van de server.</string>
<string name="default_route_summary">Leid al het Verkeer over de VPN</string>
<string name="use_default_title">Gebruik standaard Route</string>
+ <string name="custom_route_message">Aangepaste routes invoeren. Voer alleen de bestemming in CIDR-formaat. \"10.0.0.0/8 2002::/16\" zou de netwerken 10.0.0.0/8 en 2002::/16 via de VPN routeren.</string>
+ <string name="custom_route_message_excluded">Routes die niet via de VPN moeten worden gerouteerd. Gebruik dezelfde syntaxis als voor opgenomen routes.</string>
<string name="custom_routes_title">Eigen routes</string>
+ <string name="custom_routes_title_excluded">Uitgesloten netwerken</string>
+ <string name="log_verbosity_level">Logging nivo</string>
<string name="float_summary">Geverifieerde pakketen zijn vanuit elk IP toegestaan</string>
<string name="float_title">Zwevende server toestaan</string>
<string name="custom_options_title">Aangepaste Opties</string>
<string name="edit_vpn">VPN Instellingen Bewerken</string>
<string name="remove_vpn_query">De VPN-profiel \'%s\' verwijderen?</string>
+ <string name="tun_open_error">Fout bij het openen van de tun interface</string>
<string name="error">"Fout:"</string>
<string name="clear">Leeg maken</string>
+ <string name="last_openvpn_tun_config">Openen tun interface:</string>
<string name="local_ip_info">Lokaal IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
+ <string name="routes_info_incl">Routes: %1$s %2$s</string>
+ <string name="routes_info_excl">Uitgesloten routes: %1$s %2$s</string>
+ <string name="routes_debug">VpnService routes geïnstalleerd: %1$s %2$s</string>
<string name="version_info">%1$s %2$s</string>
<string name="send_logfile">Logboek verzenden</string>
<string name="send">Verzenden</string>
@@ -126,5 +133,8 @@
<string name="file_icon">bestands pictogram</string>
<string name="tls_authentication">TLS Verificatie</string>
<string name="generated_config">Gegenereerde Configuratie</string>
+ <string name="generalsettings">Instellingen</string>
+ <string name="edit_profile_title">Bewerken van \"%s\"</string>
+ <string name="building_configration">Opbouwen configuratie&#8230;</string>
<string name="ipdns">IP en DNS</string>
</resources>
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index f1a2f59d..412cd1bf 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -2,8 +2,6 @@
<resources>
<string name="info">info</string>
<string name="show_connection_details">Details van de verbinding weergeven</string>
- <string name="last_openvpn_tun_config">Laatste interfaceconfiguratie van OpenVPN:</string>
- <string name="dns_domain_info">DNS Domein: %s</string>
<string name="routes_info">Routes: %s</string>
<string name="routes_info6">Routes IPv6: %s</string>
<string name="error_empty_username">De gebruikersnaam moet niet leeg zijn.</string>
diff --git a/app/src/main/res/values-no/strings-icsopenvpn.xml b/app/src/main/res/values-no/strings-icsopenvpn.xml
index 501b18df..bd71a77c 100755
--- a/app/src/main/res/values-no/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-no/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Server adresse:</string>
diff --git a/app/src/main/res/values-pl/strings-icsopenvpn.xml b/app/src/main/res/values-pl/strings-icsopenvpn.xml
index 052b0135..dece207b 100755
--- a/app/src/main/res/values-pl/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-pl/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Adres serwera:</string>
diff --git a/app/src/main/res/values-pt/strings-icsopenvpn.xml b/app/src/main/res/values-pt/strings-icsopenvpn.xml
index ec7d2534..155f9c8a 100755
--- a/app/src/main/res/values-pt/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-pt/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Endereço do Servidor:</string>
@@ -63,7 +61,9 @@
<string name="cancel_connection_long">Desconectar VPN</string>
<string name="clear_log">Limpar registo</string>
<string name="title_cancel">Cancelar Confirmação</string>
+ <string name="cancel_connection_query">Desligar a ligação actual/Cancelar tentativa de ligação?</string>
<string name="remove_vpn">Remover VPN</string>
+ <string name="check_remote_tlscert">Verifica se o servidor utiliza um certificado com extensões TLS Server (--remote-cert-tls server)</string>
<string name="check_remote_tlscert_title">Esperar certificado do servidor TLS</string>
<string name="remote_tlscn_check_title">Verificar nome de host do certificado</string>
<string name="enter_tlscn_title">Assunto do certificado remoto</string>
@@ -79,11 +79,16 @@
<string name="dns_server">Servidor DNS</string>
<string name="secondary_dns_message">Servidor DNS secundário utilizado caso o servidor primário esteja inacessível.</string>
<string name="backup_dns">Servidor DNS alternativo</string>
+ <string name="ignored_pushed_routes">Ignorar rotas empurradas</string>
+ <string name="ignore_routes_summary">Ignorar rotas definidas pelo servidor.</string>
<string name="default_route_summary">Redireccionar todo o tráfego pela VPN</string>
<string name="use_default_title">Usar rota padrão</string>
+ <string name="custom_route_message">Introduzir rotas personalizadas. Introduzir destino no formato CIDR. \"10.0.0.0/8 2002::/16\" iria direccionar as redes 10.0.0.0/8 e 2002::/16 pela VPN.</string>
+ <string name="custom_route_message_excluded">Rotas que NÃO deviam ser roteadas pela VPN. Usar a mesma sintaxe que as rotas incluídas.</string>
<string name="custom_routes_title">Rotas personalizadas</string>
<string name="custom_routes_title_excluded">Redes excluídas</string>
<string name="log_verbosity_level">Nível de verbosidade do log</string>
+ <string name="float_summary">Autoriza pacotes autenticados vindos de qualquer IP</string>
<string name="float_title">Permitir servidor flutuante</string>
<string name="custom_options_title">Opções personalizadas</string>
<string name="edit_vpn">Editar definições VPN</string>
@@ -117,6 +122,7 @@
<string name="no_vpn_support_image">A imagem não suporta a API VPNService, lamentamos :(</string>
<string name="encryption">Encriptação</string>
<string name="cipher_dialog_title">Digite o método de encriptação</string>
+ <string name="chipher_dialog_message">Introduzir o algoritmo de cifra utilizado pelo OpenVPN. Deixar vazio para usar o defeito.</string>
<string name="settings_auth">Autenticação/encriptação</string>
<string name="file_explorer_tab">Explorador de ficheiros</string>
<string name="inline_file_tab">Ficheiro embutido</string>
@@ -138,12 +144,14 @@
<string name="faq_security_title">Considerações de segurança</string>
<string name="faq_security">"Como OpenVPN é segurança sensíveis algumas notas sobre segurança são sensatas. Todos os dados no sdcard é inerentemente inseguro. Cada aplicativo pode lê-lo (por exemplo, este programa não requer direitos especiais cartão SD). Os dados desta aplicação só pode ser lido pelo próprio aplicativo. Ao usar a opção de importação para cacert / cert / chave no diálogo os dados do arquivo é armazenado no perfil de VPN. Os perfis de VPN são acessíveis apenas por esta aplicação. (Não se esqueça de apagar as cópias no sd cartão depois). Mesmo com acesso apenas por este aplicativo os dados ainda não é criptografado. torcendo por telefone ou outros exploits pode ser possível recuperar os dados. senhas salvas são armazenadas em texto simples assim. Para arquivos PKCS12 é altamente recomendável que você importá-los para o armazenamento de chaves android. "</string>
<string name="import_vpn">Importar</string>
+ <string name="broken_image_cert_title">Erro a mostrar a selecção de certificados</string>
<string name="ipv4">IPv4</string>
<string name="ipv6">IPv6</string>
<string name="speed_waiting">A esperar mensagem de estado...</string>
<string name="converted_profile">perfil importado</string>
<string name="converted_profile_i">Perfil importado %d</string>
<string name="broken_images">Imagens quebradas</string>
+ <string name="pkcs12_file_encryption_key">Chave de crifra de ficheiros PKCS12</string>
<string name="private_key_password">Senha de chave privada</string>
<string name="password">Senha</string>
<string name="file_icon">ícone de ficheiro</string>
@@ -253,4 +261,8 @@
<string name="userpw_file">Ficheiro de utilizador/senha</string>
<string name="imported_from_file">[Importado de: %s]</string>
<string name="import_log">Log de importação:</string>
+ <string name="ignore_multicast_route">Ignorar caminho multicast: %s</string>
+ <string name="ab_only_cidr">Android apenas suporta rotas CIDR para a VPN. Pelo facto de as rotas não-CIDR quase nunca serem usadas, OpenVPN para Android irá usar uma rota /32 para rotas não-CIDR e emitir um aviso.</string>
+ <string name="ab_secondary_users">VPN não funcionar para utilizadores secundários.</string>
+ <string name="ab_only_cidr_title">Rotas não CIDR</string>
</resources>
diff --git a/app/src/main/res/values-ro/strings-icsopenvpn.xml b/app/src/main/res/values-ro/strings-icsopenvpn.xml
index 3821f964..b368995d 100755
--- a/app/src/main/res/values-ro/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ro/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Adresa server:</string>
@@ -56,7 +54,7 @@
<string name="shortcut_profile_notfound">Profilul specificat în comanda rapidă nu a fost găsit</string>
<string name="random_host_prefix">Prefix host aleator</string>
<string name="random_host_summary">Adaugă 6 caractere aleatoare în faţa hostname</string>
- <string name="custom_config_title">Activare opţiuni particularizate</string>
+ <string name="custom_config_title">Activează opţiunile particularizate</string>
<string name="custom_config_summary">Specificaţi opţiunile particularizate. Folosiţi cu grijă!</string>
<string name="route_rejected">Rută respinsă de Android</string>
<string name="cancel_connection">Deconectaţi</string>
diff --git a/app/src/main/res/values-ru/strings-icsopenvpn.xml b/app/src/main/res/values-ru/strings-icsopenvpn.xml
index 5db415df..4af9e15c 100755
--- a/app/src/main/res/values-ru/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ru/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Адрес сервера:</string>
@@ -324,4 +322,5 @@
<string name="files_missing_hint">Некоторые файлы не найдены. Выберите файлы для импорта в профиль:</string>
<string name="openvpn_is_no_free_vpn">Для использования данного приложения Вам необходим VPN провайдер/шлюз поддерживающий OpenVPN. Для получения информации по настройке собственного OpenVPN сервера: http://community.openvpn.net/</string>
<string name="import_log">Лог импорта:</string>
+ <string name="ip_looks_like_subnet">VPN топологии «%3$s» указан но ifconfig %1$s %2$s выглядит больше как IP-адрес с маской сети. Если топология «подсеть».</string>
</resources>
diff --git a/app/src/main/res/values-sv/strings-icsopenvpn.xml b/app/src/main/res/values-sv/strings-icsopenvpn.xml
index 151742a5..6ef522c4 100755
--- a/app/src/main/res/values-sv/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-sv/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Serveradress:</string>
diff --git a/app/src/main/res/values-tr/strings-icsopenvpn.xml b/app/src/main/res/values-tr/strings-icsopenvpn.xml
index ea81d3ed..106f407f 100755
--- a/app/src/main/res/values-tr/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-tr/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Sunucu adresi:</string>
@@ -90,6 +88,7 @@
<string name="default_route_summary">Tüm trafiği VPN üzerinden kullan</string>
<string name="use_default_title">Varsayılan Yolu kullan</string>
<string name="custom_route_message">Özel yolları girin. CIDR biçimde tek hedef girin. \"10.0.0.0 / 8 2002 :: / 16\" ağlar VPN üzerinden 10.0.0.0 / 8 ve 2002 :: / 16 doğrudan.</string>
+ <string name="custom_route_message_excluded">VPN üzerinden yönlendirilir olmaMAlıdır Yolları. Dahil rotalar için aynı sözdizimini kullanın.</string>
<string name="custom_routes_title">Özel Yollar</string>
<string name="custom_routes_title_excluded">Dışlanan Ağlar</string>
<string name="log_verbosity_level">Ayrıntı düzeyi Log</string>
@@ -105,6 +104,9 @@
<string name="last_openvpn_tun_config">Açılış tun arabirimi:</string>
<string name="local_ip_info">Yerel IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
<string name="dns_server_info">DNS sunucusu: %1$s, etki alanı: %2$s</string>
+ <string name="routes_info_incl">Routes: %1$s %2$s</string>
+ <string name="routes_info_excl">Routes excluded: %1$s %2$s</string>
+ <string name="routes_debug">VPN Servis Yolları Yüklendi: %1$s %2$s</string>
<string name="ip_not_cidr">Arabirim bilgileri %1$s ve %2$s var, tabii ikinci eş adresi uzaktan adresidir. /32 Kullanarak için yerel IP ağ maskesi. OpenVPN tarafından verilen \"%3$s\" modudur.</string>
<string name="route_not_cidr">%1$s ve %2$s olarak IP yolu ile CIDR ağ maskesi, ağ maskesi /32 kullanarak yapamazsınız.</string>
<string name="route_not_netip">Rota %1$s/%2$s %3$s/%2$s için düzeltilmiş</string>
@@ -332,5 +334,15 @@
<string name="server_list">Sunucu Listesi</string>
<string name="vpn_allowed_apps">İzin verilen uygulamalar</string>
<string name="advanced_settings">Gelişmiş Ayarlar</string>
+ <string name="payload_options">Yük seçenekleri</string>
<string name="tls_settings">TLS Ayarları</string>
+ <string name="show_log">Günlüğü göster</string>
+ <string name="ab_proxy_title">VPN\'ler için Proxy davranışı</string>
+ <string name="ab_lollipop_reinstall_title">VPN uygulamaları yeniden yükleme</string>
+ <string name="version_upto">%s ve önceki</string>
+ <string name="copy_of_profile">%s kopyası</string>
+ <string name="ab_kitkat_mss_title">VPN bağlantısı için yanlış MSS değeri</string>
+ <string name="ab_secondary_users_title">İkincil tablet kullanıcıları</string>
+ <string name="custom_connection_options_warng">Özel bağlantı seçenekleri belirtin. Dikkatli kullanın</string>
+ <string name="custom_connection_options">Özel Seçenekler</string>
</resources>
diff --git a/app/src/main/res/values-uk/strings-icsopenvpn.xml b/app/src/main/res/values-uk/strings-icsopenvpn.xml
index dbbc65a0..35d20e8b 100755
--- a/app/src/main/res/values-uk/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-uk/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">Адреса сервера:</string>
@@ -65,7 +63,7 @@
<string name="title_cancel">Підтвердження скасування</string>
<string name="cancel_connection_query">Відключення активних VPN/скасувати спробу підключення?</string>
<string name="remove_vpn">Видалити VPN</string>
- <string name="check_remote_tlscert">Перевіряє, чи є сервер використовує сертифікат з сервера TLS розширень (--remote-cert-tls server)</string>
+ <string name="check_remote_tlscert">Перевіряє, чи використовує сервер сертифікат з TLS розширень сервера (--remote-cert-tls server)</string>
<string name="check_remote_tlscert_title">Очікувати TLS сертифікат сервера</string>
<string name="remote_tlscn_check_summary">Перевірка DN об\'єкта віддаленого сертифіката</string>
<string name="remote_tlscn_check_title">Перевірка імені вузла сертифікату</string>
@@ -89,6 +87,7 @@
<string name="default_route_summary">Перенаправляти увесь трафік через VPN</string>
<string name="use_default_title">Використовувати типовий маршрут</string>
<string name="custom_route_message"> Введіть користувацькі маршрути. Тільки введіть адресу призначення в форматі CIDR. \"10.0.0.0/8 2002::/16\" буде використано для 10.0.0.0/8 і 2002::/16 мереж через VPN.</string>
+ <string name="custom_route_message_excluded">Маршрути які НЕ СЛІД направляти через VPN. Використовуйте той-же синтаксис як і у випадку з іншими маршрутами.</string>
<string name="custom_routes_title">Власні маршрути</string>
<string name="custom_routes_title_excluded">Виключені Мережі</string>
<string name="log_verbosity_level">Рівень деталізації журналу</string>
@@ -128,6 +127,7 @@
<string name="no_vpn_support_image">Ваша прошивка не підтримує VPNService API, вибачте :(</string>
<string name="encryption">Шифрування</string>
<string name="cipher_dialog_title">Введіть метод шифрування</string>
+ <string name="chipher_dialog_message">Вкажіть алгоритм шифрування, для використання OpenVPN. Залиште пустим, якщо треба шифрування за замовчуванням.</string>
<string name="auth_dialog_message">Введіть the authentication digest для OpenVPN. Залиште порожнім для використання стандартних значень.</string>
<string name="settings_auth">Автентифікація/Шифрування</string>
<string name="file_explorer_tab">Провідник файлів</string>
@@ -143,7 +143,7 @@
<string name="add_profile">додати профіль</string>
<string name="import_could_not_open">Не можливо знайти файл %1$s, згаданий у імпортованому файлі конфігурації</string>
<string name="importing_config">Імпорт файлу конфігурації з джерела %1$s</string>
- <string name="import_warning_custom_options">Ваша конфігурація мала кілька варіантів конфігурації, які не відображені в інтерфейсі конфігурації. Ці варіанти були додані в якості користувача параметрів конфігурації. Призначена для користувача конфігурація відображається нижче:</string>
+ <string name="import_warning_custom_options">Ваша конфігурація мала декілька налаштувань, які не відображені в інтерфейсі конфігурації. Ці варіанти були додані в конфігурації в розділ параметрів користувача. Користувацька конфігурація відображається нижче:</string>
<string name="import_done">Файл конфігурації успішно прочитаний.</string>
<string name="nobind_summary">Не прив\'язувати до локальної адреси і порту</string>
<string name="no_bind">Нема локальної прив\'язки</string>
@@ -184,7 +184,7 @@
<string name="error_rsa_sign">Помилка підпису з використанням ключа із сховища Андроїд %1$s: %2$s</string>
<string name="faq_system_dialogs">Попередження VPN з\'єднання повідомляє вам, що цей додаток може перехоплювати весь мережевий трафік, і повідомляється системою попереджень VPNService API. \nСповіщення про VPN з\'єднання (символ \"Ключа\") також формується системою Android для сигналізації про вихідне VPN з\'єднання. У деяких прошивках це сповіщення супроводжується сигналом. \nAndroid використовує ці cповіщення для вашої власної безпеки і їх не можна обійти. (На жаль, на деяких прошивках також сповіщення супроводжується звуком)</string>
<string name="faq_system_dialogs_title">Повідомлення про підключення та звук сповіщеня</string>
- <string name="translationby">Переклад українською від wvolov</string>
+ <string name="translationby">Переклад українською виконан спільнотою code.google.com</string>
<string name="ipdns">IP-адреса та DNS</string>
<string name="basic">Основне</string>
<string name="routing">Маршрутизація</string>
@@ -193,6 +193,7 @@
<string name="export_config_title">ICS Openvpn конфігурація</string>
<string name="warn_no_dns">Жодний DNS сервер не використовується. Дозвіл імен може не працювати. Розгляньте питання про створення користувацьких серверів DNS. Зверніть увагу, що Android буде продовжувати використовувати налаштування проксі-сервера, вказаного для вашого мобільного / Wi-Fi з\'єднання, коли не задано DNS сервери.</string>
<string name="dns_add_error">Не можливо додати DNS-сервер \"%1$s\", відхилено системою: %2$s</string>
+ <string name="ip_add_error">Не вдалося налаштувати IP-адресу \"%1$s\", відхилено системою: %2$s</string>
<string name="faq_howto">&lt;p&gt; Використовуйте готову конфігурацію (протестовану на вашому комп\'ютері або отриману від вашого провайдера) &lt;/p&gt; &lt;p&gt; Якщо це простий файл без pem/pks12 ви можете відправити його по email на свій пристрій. Якщо ж це декілька файлів, ви можете використовувати їх зі своєї карти пам\'яті. &lt;/p&gt; &lt;p&gt; Просто натисніть на .сonf файл або виберіть його за допомогою меню в програмі для імпорту конфігурації &lt;/p&gt; &lt;p&gt; Якщо програма видасть помилку про брак деяких файлів, просто помістіть ці файли на карту пам\'яті &lt;/p&gt; &lt;p&gt; Натисніть Збереження для додавання імпортованої конфігурації в програму &lt;/p&gt; &lt;p&gt; Запустіть ваш VPN-тунель, натиснувши на його назву в списку &lt;/p&gt; &lt;p&gt; Якщо при запуску виникли помилки спробуйте розібратися і усунути їх. &lt;/p&gt;</string>
<string name="faq_howto_title">Швидкий старт</string>
<string name="setting_loadtun_summary">Спробуйте завантажити модуль ядра tun.ko перш ніж з\'єднатися. Необхідний пристрій з правами root.</string>
@@ -210,15 +211,16 @@
<string name="restart_vpn_after_change">Після перезапуску VPN застосувати зміни конфігурації. (Пере)запустити VPN тепер?</string>
<string name="configuration_changed">Конфігурація змінена</string>
<string name="log_no_last_vpn">Не вдалося визначити останній підключений профіль для редагування</string>
- <string name="faq_duplicate_notification_title">Дублювати сповіщення</string>
+ <string name="faq_duplicate_notification_title">Повторювати повідомлення</string>
<string name="faq_duplicate_notification">Якщо в Android виникає нестача оперативної пам\'яті (RAM), непотрібні служби і програми зупиняються. Через це переривається встановлене VPN-з\'єднання. Щоб уникнути цього, програму потрібно запускати з підвищеним пріоритетом. Для запуску з високим пріоритетом програма повинна вивести попередження. Піктограма ключа сповіщення виводиться системою, як описано в попередньому пункті ЧаП. Це не вважається як програмне сповіщення з метою запуску з вищим пріоритетом.</string>
<string name="no_vpn_profiles_defined">VPN профіль не визначено.</string>
<string name="add_new_vpn_hint">Використовуйте &lt;img src=\"ic_menu_add\"/&gt; піктограму для додання нової VPN</string>
- <string name="vpn_import_hint">Використовуйте &lt;img src=\"ic_menu_archive\"/&gt; піктограму для імпорту існуючого (.ovpn or .conf) профілю з вашої карти пам\'яті.</string>
+ <string name="vpn_import_hint">Використовуйте &lt;img src=\"ic_menu_archive\"/&gt; піктограму для імпорту існуючого (.ovpn чи .conf) профілю з вашої карти пам\'яті.</string>
<string name="faq_hint">Не забудьте заглянути у ЧаП. Там також є короткий посібник.</string>
<string name="faq_routing_title">Конфігурація маршрутизації/інтерфейсу</string>
+ <string name="faq_routing">Налаштування маршрутизації та інтерфейсу проводиться не через традиційні команди ifconfig/route, а за допомогою VPNService API. Це призводить до створення іншій конфігурації маршрутизації, відмінної від конфігурацій, використовуваних на інших ОС. \nКонфігурація VPN-тунелю складається з IP-адрес і мереж, які повинні направлятися через цей інтерфейс. Ніяких особливих партнерських адреса або адреса шлюзу не потрібно. Також не потрібні і спеціальні маршрути для з\'єднання з VPN-сервером (наприклад, додані при використанні redirect-gateway). Тому, програма буде ігнорувати ці параметри при імпорті конфігурації. Програма за допомогою VPNService API гарантує, що підключення до сервера не надсилається через VPN-тунель.\nПідтримуэться напрямок через тунель тільки певних мереж. Програма намагається визначити мережі, які не повинні бути спрямовані через тунель (наприклад, route x.x.x.x y.y.y.y net_gateway) і обчислює список маршрутів, в який не включаються ці маршрути, щоб емулювати поведінку на інших платформах. Вікна журналів і логів показують конфігурацію сервісу VPN після встановлення з\'єднання.\nЗа кулісами : в Android 4.4+ не використовуються політики маршрутизації. Використання route/ifconfig не покаже які встановлени маршрути. Замість цього використовуйте ip правила, iptables -t mangle -L</string>
<string name="persisttun_summary">Не повертатися до жодного VPN з\'єднання, коли OpenVPN перепідключається.</string>
- <string name="persistent_tun_title">Стійкість tun</string>
+ <string name="persistent_tun_title">Постійний tun</string>
<string name="openvpn_log">Журнал OpenVPN</string>
<string name="import_config">Імпорт конфігурації OpenVPN</string>
<string name="battery_consumption_title">Споживання акумулятора</string>
@@ -273,27 +275,103 @@
<string name="tls_remote_deprecated">tls-remote (ЗАСТАРІЛЕ)</string>
<string name="help_translate">Ви можете допомогти в перекладі, відвідавши http://crowdin.net/project/ics-openvpn/invite</string>
<string name="prompt">%1$s спроб контролювати %2$s</string>
+ <string name="remote_warning">Продовжуючи, ви даєте дозвіл на застосування повного контролю OpenVPN для Android і щоб перехоплювати весь мережевий трафік.<b>Не приймайте, якщо ви не довіряєте програмі.</b> В іншому випадку ви ризикуєте мати скомпрометовані шкідливим програмним забезпеченням дані.\"</string>
<string name="remote_trust">Я довіряю цьому додатку.</string>
<string name="no_external_app_allowed">Не дозволяється використовувати зовнішнє API</string>
<string name="allowed_apps">Дозволенi додатки: %s</string>
<string name="clearappsdialog">Очистити список дозволених зовнішніх програм \nПоточний список дозволених програм:\n\n%s</string>
- <string name="screenoff_summary">&quot;Пауза VPN, коли екран вимкнений і менш ніж 64 Кб переданих даних за 60с. Коли „Постійний тун“ увімкнений пауза VPN залишить ваш пристрій без відсутності мережевого підключення. Без параметра „Постійний тун“ пристрій не буде мати ніякого VPN підключення / захисту.</string>
+ <string name="screenoff_summary">\"Пауза VPN, коли екран вимкнений і менш ніж 64 кб були передані за 60 секунд. Якщо увімкена опція \"Постійний tun\", то Пауза VPN залишить ваш пристрій БЕЗ мережевого підключення. Без опції \"Постійний tun\", пристрій використовує нормальне (незахище) підключення до інтернету, коли VPN в паузі.</string>
<string name="screenoff_title">Пауза VPN з\'єднання після вимкнення екрану</string>
<string name="screenoff_pause">Призупинення зв\'язку в екрані вимкненого стану: менше %1$s у %2$sс.</string>
- <string name="screen_nopersistenttun">Попередження: Постійний тут не увімкнений для цього VPN. Трафік буде використовувати звичайне інтернет-з\'єднання, коли екран вимкнений.</string>
+ <string name="screen_nopersistenttun">Попередження: Постійний tun не увімкнений для цього VPN. Трафік буде використовувати звичайне інтернет-з\'єднання, коли екран вимкнений.</string>
<string name="save_password">Зберегти пароль</string>
<string name="pauseVPN">Призупинити VPN</string>
<string name="resumevpn">Відновити VPN</string>
+ <string name="state_userpause">VPN пауза на вимогу користувача</string>
+ <string name="state_screenoff">VPN призупинено - screen off</string>
+ <string name="device_specific">Хак для цього пристрою</string>
<string name="cannotparsecert">Неможливо відобразити інформацію про сертифікат</string>
+ <string name="appbehaviour">Поведінка програми</string>
<string name="vpnbehaviour">Поведінка VPN</string>
<string name="allow_vpn_changes">Дозволити зміни в профілі VPN</string>
+ <string name="hwkeychain">Апаратне сховище ключів:</string>
<string name="permission_icon_app">Іконка додатка намагається використовувати OpenVPN для Android</string>
+ <string name="faq_vpndialog43">"Починаючи з Android 4.3, запит підтвердження VPN-з\'єднання захищено від програм, які \"накладаються поверх екрану\". Це призводить до того, що діалогове вікно підтвердження не реагує на сенсорні натискання. Якщо у вас є програма, що використовує накладення, то це може викликати таке поведінку. Якщо ви виявите де-небудь таку програмe, зв\'яжіться з автором програми Ця проблема зачіпає всі VPN програми на Android 4.3 та пізніших версіях Дивіться також &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\"&gt;Issue 185&lt;a&gt; для отримання додаткової інформації"</string>
+ <string name="faq_vpndialog43_title">Вікно підтвердження VPN</string>
+ <string name="donatePlayStore">Також Ви можете висловити подяку у вигляді пожертвувань на Play Store:</string>
<string name="thanks_for_donation">Дякуємо за пожертвування %s!</string>
<string name="logCleared">Журнал очищено.</string>
<string name="show_password">Показати пароль</string>
+ <string name="keyChainAccessError">Помилка при доступі до сховища ключів:%s</string>
+ <string name="timestamp_short">Стисло</string>
<string name="timestamp_iso">ISO</string>
<string name="timestamps">Часові позначки</string>
+ <string name="timestamps_none">Нема</string>
+ <string name="uploaded_data">Вивантажено</string>
+ <string name="downloaded_data">Завантажити</string>
+ <string name="vpn_status">Vpn Статус</string>
+ <string name="logview_options">Подивитися налаштування</string>
+ <string name="unhandled_exception">Невідома помилка: %1$s\n\n%2$s</string>
+ <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
+ <string name="faq_system_dialog_xposed">Якщо на Вашому пристрої встановлені root права, Ви можете встановити &lt;a href=\"http://xposed.info/\"&gt;Xposed framework&lt;/a&gt; та &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;VPN Dialog confirm module&lt;/a&gt; на свій страх і ризик\"</string>
<string name="full_licenses">Повні ліцензії</string>
+ <string name="blocklocal_summary">Мережі, безпосередньо доступні через локальний інтерфейс не направлятимуться на VPN. Відключіть цю опцію щоб направити увесь трафік через VPN.</string>
+ <string name="blocklocal_title">Не використовувати VPN для локальних мереж</string>
+ <string name="userpw_file">Файл з Ім\'ям користувача та Паролєм</string>
<string name="imported_from_file">[Імпортовано з: %s]</string>
+ <string name="files_missing_hint">Деякі файли не були знайдені. Будь ласка, виберіть файли для імпорту профілю:</string>
+ <string name="openvpn_is_no_free_vpn">Щоб користуватися цією програмою, Вам знадобиться VPN провайдер/шлюз з підтримкою OpenVPN (часто наданий роботодавцем). Для отримання інформації з налаштування власного OpenVPN сервера: http://community.openvpn.net/</string>
<string name="import_log">Журнал імпорту :</string>
+ <string name="ip_looks_like_subnet">Vpn топологія \"%3$s\" визначена, але ifconfig %1$s %2$s більше схожий на IP-адресу з маскою мережі. Припускаемо, що це топологія \"мережі\".</string>
+ <string name="mssfix_invalid_value">Значення MSS являє собою ціле число від 0 до 9000</string>
+ <string name="mssfix_value_dialog">Зміни в TCP з\'єднанні, які проходять через тунель, так що отриманий в результаті розмір пакета UDP, після инкапсуляції по OpenVPN обмежується цим значенням. (За замовчуванням 1450)</string>
+ <string name="mssfix_checkbox">Зміна значення MSS навантаження TCP</string>
+ <string name="mssfix_dialogtitle">Встановка значення MSS навантаження TCP</string>
+ <string name="client_behaviour">Поведінка VPN</string>
+ <string name="clear_external_apps">Відкликати права для управління OpenVPN</string>
+ <string name="loading">Завантаження&#8230;</string>
+ <string name="allowed_vpn_apps_info">Дозволенi VPN програми: %1$s</string>
+ <string name="disallowed_vpn_apps_info">Заборонені VPN програми: %1$s</string>
+ <string name="app_no_longer_exists">Пакет програм з ім\'ям %s не встановлений, та буде вилучений зі списку дозволених/заборонених VPN програм.</string>
+ <string name="vpn_disallow_radio">VPN використовується для всіх програм, але виключити вибрані</string>
+ <string name="vpn_allow_radio">VPN використовується тільки для обраних програм</string>
+ <string name="query_delete_remote">Видалити запис про сервер?</string>
+ <string name="keep">Втримати</string>
+ <string name="delete">Видалити</string>
+ <string name="add_remote">Додати новий сервер</string>
+ <string name="remote_random">Використовувать список серверів у випадковому порядку при підключенні</string>
+ <string name="remote_no_server_selected">Вам потрібно вказати і включити принаймні один сервер.</string>
+ <string name="server_list">Список серверів</string>
+ <string name="vpn_allowed_apps">Дозволенi програми</string>
+ <string name="advanced_settings">Додаткові налаштування</string>
+ <string name="payload_options">Варіанти Payload</string>
+ <string name="tls_settings">Налаштування TLS</string>
+ <string name="no_remote_defined">Не визначен сервер</string>
+ <string name="duplicate_vpn">Дублікат VPN профіля</string>
+ <string name="duplicate_profile_title">Дублікат VPN профіля: %s</string>
+ <string name="show_log">Показати журнал</string>
+ <string name="faq_android_clients">Є декілька клієнтів для Android OpenVPN. Найбільш поширеним є OpenVPN for Android (цей клієнт), OpenVPN Connect і OpenVPN Settings.&lt;p&gt;Клієнти можуть бути розділені на дві групи: OpenVPN for Android і OpenVPN Connect використовують офіційний VPNService API (Android 4.0+), який не вимагає права root, та OpenVPN Settings який використовує зміну маршрутизації (потребує root права).&lt;p&gt;OpenVPN for Android розроблено Arne Schwabe і є безкоштовним клієнтом з відкритим ісходним кодом. Клієнт орієнтован на більш просунутих користувачів, пропонуючи безліч варіантів в рамках програми, і можливість імпорту профілів з файлів конфігурації/зміни. Клієнт на основі безкоштовної версії OpenVPN спільноти, який заснован на OpenVPN 2.x коді. Цей клієнт можна розглядати як напівофіційний безкоштовний клієнт.&lt;p&gt;OpenVPN Connect не є клієнтом з відкритим кодом, він розвивається OpenVPN Technologies, Inc. Даний клієнт призначений для загального користування, і спрямована на середнього користувача, він дозволяє імпорт профілів OpenVPN. Цей клієнт виконан на основі OpenVPN C++ протоколу OpenVPN(Це необхідно для дозволу OpenVPN Technologies, Inc. опублікувати версію iOS програми OpenVPN). Цей клієнт є офіційним OpenVPN technologies клієнтом &lt;p&gt; OpenVPN Settings є найстарішим із трьох згаданих, і також безкоштовниї OpenVPN клієнт з відкритим ісходним кодом. На відміну від OpenVPN для Android вимагає root права і не використовує VPNService API. Таким чином, вона також буде працювати в більш ранніх версіях як Android 4.0+</string>
+ <string name="faq_androids_clients_title">Відмінності між клієнтами OpenVPN для Android</string>
+ <string name="ignore_multicast_route">Ігнорувати multicast маршрут:%s</string>
+ <string name="ab_only_cidr">Android підтримує тільки CIDR маршрути для VPN. Так, не-CIDR маршрути майже ніколи не використовуються, OpenVPN for Android використовує /32 для маршрутів, які не є CIDR і видає попередження.</string>
+ <string name="ab_tethering_44">Загальний доступ до підключення (WiFi точки/модему) працює як VPN активний, але НЕ використовує VPN.</string>
+ <string name="ab_kitkat_mss">Рання версія KitKat встановлюе невірне значення MSS з\'єднань TCP (#61948). OpenVPN активує опцію mssfix щоб обійти цю проблему.</string>
+ <string name="ab_proxy">Android буде продовжувати використовувати налаштування проксі-сервера для мобільного зв\'язку/Wi-Fi, коли немає встановленого DNS-сервера. OpenVPN for Android попередить вас про це в журналі.<p>Коли VPN встановить DNS-сервер Android не буде використовувати проксі-сервер. Зараз немає API для використання проксі-серверу для VPN-підключення.</p></string>
+ <string name="ab_lollipop_reinstall">VPN програма може перестати працювати, як вона була видалена і перевстановлена знову. Більш детальну інформацію дивіться #80074</string>
+ <string name="ab_not_route_to_vpn">Налаштований клієнтом IP і IP-адреси в цій мережевій масці не направляються до VPN. OpenVPN обробляє цю помилку явно додаючи маршрут, який відповідає IP клієнта і його маскою мережі</string>
+ <string name="ab_persist_tun">Відкриття tun пристрію поки інший tun пристрій активний, який використовує persist-tun, приводе до аварії VPNServices на пристрої. Потрібне перезавантаження, щоб VPN запрацював знову. OpenVPN for Android намагається уникнути повторне відкриття tun пристрію, а якщо дійсно необхідно в першу чергу закриває поточний TUN перед відкриттям нового TUN пристрої, щоб уникнути помилки. Це може призвести до виникнення короткого вікна, в якому пакети пересилаються по мережі без VPN. Навіть це тимчасове рішення іноді призводить до краху VPNServices і вимагає перезавантаження пристрою.</string>
+ <string name="ab_secondary_users">VPN не працює для других користувачів.</string>
+ <string name="ab_kitkat_reconnect">"Декілька користувачів повідомили, що мобільний зв\'язок/мобільні дані часто відключається, коли VPN активний. Поведінка, здається, впливає тільки для комбінації деякіх провайдерів/пристріїв і досі ні причини, ні рішення для цієї помилки не визначені. "</string>
+ <string name="ab_vpn_reachability_44">Тільки призначення, які досяжні без VPN, також доступні по VPN. IPv6 VPN не працює взагалі.</string>
+ <string name="ab_only_cidr_title">Несумісні CIDR маршрути</string>
+ <string name="ab_proxy_title">Поведінка проксі для VPN</string>
+ <string name="ab_lollipop_reinstall_title">Перевстановлення VPN-програми</string>
+ <string name="version_upto">%s і раніше</string>
+ <string name="copy_of_profile">Копія %s</string>
+ <string name="ab_not_route_to_vpn_title">Шлях до налаштованого VPN IP адреса</string>
+ <string name="ab_kitkat_mss_title">Невірне значення MSS для VPN підключення</string>
+ <string name="ab_secondary_users_title">Другі користувачі планшету</string>
+ <string name="custom_connection_options_warng">Визначені параметри користувача при з\'єднанні. Будьте обережні!</string>
+ <string name="custom_connection_options">Власні налаштовування</string>
+ <string name="remove_connection_entry">Видалити запис підключення</string>
</resources>
diff --git a/app/src/main/res/values-v21/refs.xml b/app/src/main/res/values-v21/refs.xml
index a4a26bec..2a09271d 100644
--- a/app/src/main/res/values-v21/refs.xml
+++ b/app/src/main/res/values-v21/refs.xml
@@ -5,10 +5,10 @@
-->
<resources>
- <drawable name="ic_menu_close_clear_cancel">@drawable/ic_close_white_24dp</drawable>
- <drawable name="ic_menu_share">@drawable/ic_share_white_24dp </drawable>
- <drawable name="ic_menu_save">@drawable/ic_check_white_24dp</drawable>
- <drawable name="ic_menu_view">@drawable/ic_filter_list_white_24dp</drawable>
- <drawable name="ic_menu_delete">@drawable/ic_delete_white_24dp</drawable>
- <drawable name="ic_menu_delete_grey">@drawable/ic_delete_grey600_24dp</drawable>
+ <drawable name="ic_menu_close_clear_cancel">@drawable/ic_close_white_24dp</drawable>
+ <drawable name="ic_menu_share">@drawable/ic_share_white_24dp </drawable>
+ <drawable name="ic_menu_save">@drawable/ic_check_white_24dp</drawable>
+ <drawable name="ic_menu_view">@drawable/ic_filter_list_white_24dp</drawable>
+ <drawable name="ic_menu_delete">@drawable/ic_delete_white_24dp</drawable>
+ <drawable name="ic_menu_delete_grey">@drawable/ic_delete_grey600_24dp</drawable>
</resources>
diff --git a/app/src/main/res/values-vi/strings-icsopenvpn.xml b/app/src/main/res/values-vi/strings-icsopenvpn.xml
new file mode 100755
index 00000000..42f07ee8
--- /dev/null
+++ b/app/src/main/res/values-vi/strings-icsopenvpn.xml
@@ -0,0 +1,377 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!--
+ ~ Copyright (c) 2012-2014 Arne Schwabe
+ ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
+ -->
+<resources>
+
+ <string name="address">Địa chỉ máy chủ:</string>
+ <string name="port">Cổng máy chủ:</string>
+ <string name="location">Vị trí</string>
+ <string name="cant_read_folder">Không thể đọc thư mục</string>
+ <string name="select">Chọn</string>
+ <string name="cancel">Hủy bỏ</string>
+ <string name="no_data">Không có dữ liệu</string>
+ <string name="useLZO">LZO Nén</string>
+ <string name="client_no_certificate">Không chứng nhận</string>
+ <string name="client_certificate_title">Chứng nhận máy trạm</string>
+ <string name="client_key_title">Khóa chứng nhận máy trạm</string>
+ <string name="client_pkcs12_title">Tập tin PKCS12</string>
+ <string name="ca_title">Chứng nhận CA</string>
+ <string name="no_certificate">Bạn phải chọn một chứng chỉ</string>
+ <string name="copyright_guicode">Mã nguồn và theo dõi lỗi hiện có tại http://code.google.com/p/ics-openvpn/</string>
+ <string name="copyright_others">Chương trình này sử dụng các thành phần sau: xem mã nguồn đầy đủ trong giấy phép</string>
+ <string name="about">Thông tin ứng dụng</string>
+ <string name="vpn_list_title">Hồ sơ</string>
+ <string name="vpn_type">Loại</string>
+ <string name="pkcs12pwquery">Mật khẩu PKCS12</string>
+ <string name="file_select">Chọn&#8230;</string>
+ <string name="file_nothing_selected">Bạn phải chọn một tập tin</string>
+ <string name="useTLSAuth">Sử dụng xác thực TLS</string>
+ <string name="tls_direction">Hướng TLS</string>
+ <string name="ipv6_dialog_tile">Nhập địa chỉ IPv6/Netmask trong định dạng CIDR (ví dụ 2000:dd::23/64)</string>
+ <string name="ipv4_dialog_title">Nhập địa chỉ IPv4/Netmask trong định dạng CIDR (ví dụ 1.2.3.4/24)</string>
+ <string name="ipv4_address">Địa chỉ IPv4</string>
+ <string name="ipv6_address">Địa chỉ IPv6</string>
+ <string name="custom_option_warning">Nhập tùy chọn cá nhân Open VPN. Sử dụng thận trọng. Lưu ý các thiết lập OpenVPN không thể hỗ trợ bởi thiết kế cấu hình của VPN. Nếu bạn thấy tùy chọn quan trọng hoặc mất mát, bạn có thể liên hệ với tác giả</string>
+ <string name="auth_username">Tên người dùng</string>
+ <string name="auth_pwquery">Mật khẩu</string>
+ <string name="static_keys_info">Đối với cấu hình tĩnh thì khóa TLS sẽ được dùng như khóa tĩnh</string>
+ <string name="configure_the_vpn">Cấu hình VPN</string>
+ <string name="menu_add_profile">Thêm hồ sơ</string>
+ <string name="add_profile_name_prompt">Nhập một tên để xác định hồ sơ mới</string>
+ <string name="duplicate_profile_name">Vui lòng nhập một tên hồ sơ duy nhất</string>
+ <string name="profilename">Tên hồ sơ</string>
+ <string name="no_keystore_cert_selected">Bạn phải chọn một chứng chỉ người dùng</string>
+ <string name="no_error_found">Không tìm thấy lỗi</string>
+ <string name="config_error_found">Lỗi trong cấu hình</string>
+ <string name="ipv4_format_error">Lỗi phân tích cú pháp địa chỉ IPv4</string>
+ <string name="custom_route_format_error">Lỗi phân tích cú pháp định tuyến tùy chỉnh</string>
+ <string name="pw_query_hint">(để trống để truy vấn theo yêu cầu)</string>
+ <string name="vpn_shortcut">Lối tắt Open VPN</string>
+ <string name="vpn_launch_title">Kết nối đến VPN</string>
+ <string name="shortcut_profile_notfound">Hồ sơ quy định tại lối tắt không tìm thấy</string>
+ <string name="random_host_prefix">Tiền tố miền ngẫu nhiên</string>
+ <string name="random_host_summary">Thêm 6 ký tự ngẫu nhiên ở phía trước tên miền</string>
+ <string name="custom_config_title">Kích hoạt tùy chỉnh</string>
+ <string name="custom_config_summary">Chỉ định các tùy chỉnh. Dùng cẩn thận!</string>
+ <string name="route_rejected">Định tuyến bị từ chối bởi Android</string>
+ <string name="cancel_connection">Ngắt kết nối</string>
+ <string name="cancel_connection_long">Ngắt kết nối VPN</string>
+ <string name="clear_log">xóa Nhật ký</string>
+ <string name="title_cancel">Xác nhận hủy bỏ</string>
+ <string name="cancel_connection_query">Ngắt kết nối VPN/hủy bỏ nỗ lực kết nối?</string>
+ <string name="remove_vpn">Loại bỏ VPN</string>
+ <string name="check_remote_tlscert">Kiểm tra máy chủ sử dụng chứng nhận với các phần mở rộng máy chủ TLS (--remote-cert-tls server)</string>
+ <string name="check_remote_tlscert_title">Đợi chứng chỉ máy chủ TLS</string>
+ <string name="remote_tlscn_check_summary">Kiểm tra Chứng chỉ máy chủ từ xa</string>
+ <string name="remote_tlscn_check_title">Kiểm tra chứng chỉ tên miền</string>
+ <string name="enter_tlscn_dialog">Xác định để kiểm tra sử dụng chứng nhận từ xa DN (e.g. C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\nHoàn chỉnh các DN hoặc RDN (openvpn.blinkt.de làm ví dụ) hoặc một tiền tố RDN để xác minh.\n\nKhi dùng tiền tố RDN phù hợp \"Server-1\" và \"Server-2\"\n\nĐể trường văn bản trống sẽ kiểm tra tiền tố RDN phản biện tên miền máy chủ. \n\nĐể biết thêm chi tiết xem tại phần quản lý OpenVPN 2.3.1+ bên dưới —xác minh-x509-tên</string>
+ <string name="enter_tlscn_title">Chủ đề chứng chỉ từ xa</string>
+ <string name="tls_key_auth">Cho phép xác thực khóa TLS</string>
+ <string name="tls_auth_file">Tập tin chứng thực TLS</string>
+ <string name="pull_on_summary">Yêu cầu các địa chỉ IP, định tuyến và tùy chọn thời gian từ máy chủ.</string>
+ <string name="pull_off_summary">Không có thông tin được yêu cầu từ máy chủ. Thiết lập cần phải được xác định bên dưới.</string>
+ <string name="use_pull">Cài đặt kéo</string>
+ <string name="dns">DNS</string>
+ <string name="override_dns">Ghi đè thiết lập DNS bởi máy chủ</string>
+ <string name="dns_override_summary">Dùng máy chủ DNS của riêng bạn</string>
+ <string name="searchdomain">Tìm tên miền</string>
+ <string name="dns1_summary">Máy chủ DNS để dùng.</string>
+ <string name="dns_server">Máy chủ DNS</string>
+ <string name="secondary_dns_message">Máy chủ DNS thứ hai được dùng nếu máy chủ DNS bình thường không thể kết nối.</string>
+ <string name="backup_dns">Sao lưu máy chủ DNS</string>
+ <string name="ignored_pushed_routes">Bỏ qua các định tuyến đẩy</string>
+ <string name="ignore_routes_summary">Bỏ qua các định tuyến đẩy bởi máy chủ.</string>
+ <string name="default_route_summary">Chuyển hướng tất cả lưu lượng qua VPN</string>
+ <string name="use_default_title">Sử dụng định tuyến mặc định</string>
+ <string name="custom_route_message">Nhập định tuyến tùy chỉnh. Chỉ nhập điểm đích trong định dạng CIDR. \"10.0.0.0/8 2002::/16\" sẽ điều hành trực tiếp mạng \"10.0.0.0/8 và 2002::/16\" qua VPN.</string>
+ <string name="custom_route_message_excluded">Định tuyến KHÔNG nên chuyển tải qua VPN. Sử dụng cú pháp tương tự như với bao gồm các định tuyến.</string>
+ <string name="custom_routes_title">Định tuyến tùy chỉnh</string>
+ <string name="custom_routes_title_excluded">Các mạng loại trừ</string>
+ <string name="log_verbosity_level">Mức độ hiển thị bản ghi</string>
+ <string name="float_summary">Cho phép các gói tin xác thực từ IP bất kỳ</string>
+ <string name="float_title">Cho phép các máy chủ nổi</string>
+ <string name="custom_options_title">Cấu hình tùy chỉnh</string>
+ <string name="edit_vpn">Chỉnh sửa cài đặt VPN</string>
+ <string name="remove_vpn_query">Loại bỏ hồ sơ VPN \'%s\'?</string>
+ <string name="tun_error_helpful">Trên một số ROM tùy chỉnh ICS cho phép trên/dev/tun có thể sai, hoặc tun module có thể bị mất hoàn toàn. Đối với ROM CM9 thử sửa lại các tùy chỉnh theo cấu hình cài đặt chung</string>
+ <string name="tun_open_error">Không thể mở giao diện tun</string>
+ <string name="error">"Lỗi: "</string>
+ <string name="clear">Xóa</string>
+ <string name="last_openvpn_tun_config">Đang mở giao diện TUN:</string>
+ <string name="local_ip_info">IPv4 địa phương: %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
+ <string name="dns_server_info">DNS Server: %1$s, Domain: %2$s</string>
+ <string name="routes_info_incl">Định tuyến: %1$s %2$s</string>
+ <string name="routes_info_excl">Định tuyến loại trừ: %1$s %2$s</string>
+ <string name="routes_debug">Dịch vụ định tuyến VPN đã cài đặt: %1$s %2$s</string>
+ <string name="ip_not_cidr">Lấy giao diện thông tin %1$s và %2$s, giả sử địa chỉ thứ hai là địa chỉ ngang hàng từ xa. Dùng mặt nạ mạng /32 cho IP địa phương. Chế độ được đưa ra bởi Open VPN là \"%3$s\".</string>
+ <string name="route_not_cidr">Không thể tạo liên kết %1$s và %2$s như định tuyến IP với định dạng CIDR, sử dụng /32 như mặt nạ mạng.</string>
+ <string name="route_not_netip">Đã sửa định tuyến %1$s / %2$s để %3$s / %2$s</string>
+ <string name="keychain_access">Không thể truy cập vào Khóa điều khoản Android. Nó có thể gây ra bởi sự nâng cấp phần mềm hoặc bởi việc phục hồi bản sao của ứng dụng/cấu hình của ứng dụng. Vui lòng chỉnh sửa và chọn lại chứng chỉ bên dưới thiết lập cơ bản để tạo lại quyền truy cập chứng chỉ.</string>
+ <string name="version_info">%1$s %2$s</string>
+ <string name="send_logfile">Gửi tập tin bản ghi</string>
+ <string name="send">Gửi</string>
+ <string name="ics_openvpn_log_file">Tập tin bản ghi ICS OpenVPN</string>
+ <string name="copied_entry">Sao chép bản ghi vào bộ nhớ tạm</string>
+ <string name="tap_mode">Chế độ kiểm tra điểm truy cập</string>
+ <string name="faq_tap_mode">Chế độ kiểm tra truy cập không thể thực hiện với API VPN không nguồn gốc. Do đó ứng dụng không thể cung cấp hỗ trợ kiểm tra truy cập</string>
+ <string name="tap_faq2">Lại lần nữa? Bạn đang đùa à? Không, chế độ kiểm tra truy cập thực sự không hỗ trợ và gửi thư yêu cầu nữa nếu nó không được hỗ trợ giúp đỡ.</string>
+ <string name="tap_faq3">Lần thứ ba? Thực tế, ta có thể viết một chế độ kiểm tra truy cập giả lập dựa trên cấu hình đã thêm thông tin nền tảng khi gửi và dải thông tin nền tảng khi nhận. Nhưng chế độ kiểm tra truy cập giả lập này cũng sẽ có thể thực hiện cho ARP và máy trạm DHCP. Tôi không biết ai đã làm việc theo hướng này. Liên hệ với tôi nếu bạn muốn bắt đầu mã hóa trên đây.</string>
+ <string name="faq">Câu hỏi thường gặp</string>
+ <string name="copying_log_entries">Đang sao chép các mục bản ghi</string>
+ <string name="faq_copying">Để sao chép một mục đăng nhập hãy nhấn và giữ trên mục đăng nhập. Để sao chép/gửi toàn bộ nhật ký sử dụng hãy dùng tùy chọn Gửi Bản Ghi. Sử dụng nút menu phần cứng nếu như nút đó không hiển thị trong GUI.</string>
+ <string name="faq_shortcut">Phím tắt để bắt đầu</string>
+ <string name="faq_howto_shortcut">Bạn có thể đặt một phím tắt truy cập OpenVPN trên màn hình chính. Tùy thuộc vào chương trình màn hình bạn sẽ phải thêm một phím tắt hoặc một widget.</string>
+ <string name="no_vpn_support_image">Hình ảnh của bạn không hỗ trợ dịch vụ VPN API, xin lỗi :(</string>
+ <string name="encryption">Mã hóa</string>
+ <string name="cipher_dialog_title">Nhập phương thức mã hóa</string>
+ <string name="chipher_dialog_message">Nhập các thuật toán mã hóa được sử dụng bởi OpenVPN. Để trống để sử dụng thuật toán mã hóa mặc định.</string>
+ <string name="auth_dialog_message">Nhập cấu hình xác thực dùng cho OpenVPN. Để trống nếu sử dụng cấu hình mặc định.</string>
+ <string name="settings_auth">Xác thực/Mã hóa</string>
+ <string name="file_explorer_tab">Duyệt tập tin</string>
+ <string name="inline_file_tab">Tập tin nội tuyến</string>
+ <string name="error_importing_file">Lỗi khi nhập tập tin</string>
+ <string name="import_error_message">Không thể nhập tập tin từ hệ thống</string>
+ <string name="inline_file_data">[[Tập tin dữ liệu nội tuyến]]</string>
+ <string name="opentun_no_ipaddr">Từ chối mở thiết bị tun khi không có thông tin IP</string>
+ <string name="menu_import">Nhập hồ sơ từ tập tin ovpn</string>
+ <string name="menu_import_short">Nhập</string>
+ <string name="import_content_resolve_error">Không thể đọc hồ sơ vừa nhập</string>
+ <string name="error_reading_config_file">Lỗi đọc tập tin cấu hình</string>
+ <string name="add_profile">Thêm hồ sơ</string>
+ <string name="import_could_not_open">Không thể tìm thấy tập tin %1$s đề cập trong tập tin cấu hình vừa nhập</string>
+ <string name="importing_config">Nhập tập tin cấu hình từ nguồn %1$s</string>
+ <string name="import_warning_custom_options">Cấu hình của bạn có vài tùy chỉnh không được tương thích với cấu hình người dùng. Những tùy chọn này đã được thêm như là cấu hình tùy chỉnh. Cấu hình tùy chỉnh được hiển thị bên dưới:</string>
+ <string name="import_done">Hoàn tất đọc tập tin cấu hình.</string>
+ <string name="nobind_summary">Đừng gán vào địa chỉ địa phương và cổng</string>
+ <string name="no_bind">Không ràng buộc địa phương</string>
+ <string name="import_configuration_file">Nhập tập tin cấu hình</string>
+ <string name="faq_security_title">Cân nhắc bảo mật</string>
+ <string name="faq_security">"Vấn đề bảo mật OpenVPN trong một số trường hợp là nhạy cảm. Tất cả dữ liệu trên thẻ nhớ vốn không an toàn. Các ứng dụng khác có thể đọc được nó (ví dụ như chương trình này không bắt buộc các quyền đặc biệt từ thẻ nhớ). Dữ liệu của ứng dụng này chỉ có thể đọc bởi chính nó. Mặc dù có thể sử dụng tùy chọn nhập vào để truy cập/xem/khóa ứng dụng bên trong dữ liệu hội thoại lưu trữ trong hồ sơ VPN. Nhưng hồ sơ VPN chỉ có thể truy cập bởi chính ứng dụng này. (Đừng quên xóa các bản sao trên thẻ nhớ sau đó). Dù có thể chỉ truy cập bằng ứng dụng này nhưng dữ liệu vẫn không được mã hóa. Việc root điện thoại hoặc khai thác các vấn đề khác có thể lấy cắp được dữ liệu. Lưu trữ mật khẩu lại trong văn bản là tốt nhất. Tập tin pkcs12 là lời khuyên tốt nhất để bạn có thể nhập chúng vào Khóa lưu trữ Android."</string>
+ <string name="import_vpn">Nhập</string>
+ <string name="broken_image_cert_title">Lỗi hiển thị lựa chọn chứng chỉ</string>
+ <string name="broken_image_cert">Có một sự cố khi cố gắng hiển thị chứng chỉ Android 4.0+ được chọn. Điều này sẽ không bao giờ xảy ra vì đây là một tính năng tiêu chuẩn của Android 4.0+. Có thể phần hỗ trợ ROM Android cho chứng chỉ được lưu trữ đã hỏng</string>
+ <string name="ipv4">IPv4</string>
+ <string name="ipv6">IPv6</string>
+ <string name="speed_waiting">Đang chờ tin nhắn trạng thái&#8230;</string>
+ <string name="converted_profile">hồ sơ đã nhập</string>
+ <string name="converted_profile_i">hồ sơ đã nhập %d</string>
+ <string name="broken_images">Ảnh bị hỏng</string>
+ <string name="broken_images_faq">&lt;p&gt;Thông tin chính thức của HTC có một số vấn đề định tuyến đường truyền xảy ra khi không lưu thông được (Xem thêm &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\"&gt;Issue 18&lt;/a&gt; trong báo cáo theo dõi lỗi).&lt;/p&gt;&lt;p&gt;Thông tin chính thức từ Sony dòng Xperia Arc S và Xperia Ray đã được báo cáo về việc mất kết nối với dịch vụ VPN. (Xem thêm &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\"&gt;Issue 29&lt;/a&gt; trong báo cáo theo dõi lỗi.)&lt;/p&gt;&lt;p&gt;Một số bản dựng tùy chỉnh cho tun module có thể bị thiếu /dev/tun hoặc có thể sai. Một vài ROM CM9 cần phải \"Sửa tùy chọn chủ sở hữu\" bên dưới \"Sự xâm nhập thiết bị cụ thể\" được bật.&lt;/p&gt;&lt;p&gt;Quan trọng nhất, nếu thiết bị của bạn hỏng ROM Android, hãy báo cáo cho nhà phát triển. Càng nhiều người báo cáo vấn đề đến nhà phát triển thì càng có nhiều khả năng họ sẽ sửa lỗi đó.&lt;/p&gt;</string>
+ <string name="pkcs12_file_encryption_key">Tập tin khóa mã hóa PKCS12</string>
+ <string name="private_key_password">Khóa mật khẩu riêng tư</string>
+ <string name="password">Mật khẩu</string>
+ <string name="file_icon">biểu tượng tập tin</string>
+ <string name="tls_authentication">Xác thực TLS</string>
+ <string name="generated_config">Tạo cấu hình</string>
+ <string name="generalsettings">Cài đặt</string>
+ <string name="owner_fix_summary">Cố gắng thiết lập chủ sở hữu của /dev/tun vào hệ thống. Một vài ROM CM9 cần việc này để thực hiện thiết lập VPN API. Yêu cầu root.</string>
+ <string name="owner_fix">Sửa quyền sở hữu /dev/tun</string>
+ <string name="generated_config_summary">Hiển thị tập tin cấu hình OpenVPN đã tạo</string>
+ <string name="edit_profile_title">Đang chỉnh sửa \"%s\"</string>
+ <string name="building_configration">Đang dựng cấu hình...</string>
+ <string name="netchange_summary">Bật tùy chọn này sẽ buộc kết nối lại nếu tình trạng mạng bị thay đổi (ví dụ Wifi đến/từ điện thoại)</string>
+ <string name="netchange">Kết nối lại khi mạng thay đổi</string>
+ <string name="netstatus">Tình trạng mạng: %s</string>
+ <string name="extracahint">Chứng chỉ CA thường trả về từ khóa lưu trữ Android. Chứng nhận riêng biệt sẽ được chỉ định nếu bạn nhận được lỗi xác minh chứng chỉ.</string>
+ <string name="select_file">Chọn</string>
+ <string name="keychain_nocacert">Không có chứng chỉ CA phản hồi khi đọc khóa lưu trữ Android. Chứng thực có thể sẽ thất bại.</string>
+ <string name="show_log_summary">Hiển thị cửa sổ đăng nhập khi kết nối. Cửa sổ đăng nhập có thể luôn truy cập từ thanh thông báo trạng thái.</string>
+ <string name="show_log_window">Hiển thị cửa sổ đăng nhập</string>
+ <string name="mobile_info">Đang chạy trên %1$s (%2$s) %3$s, Android API %4$d</string>
+ <string name="error_rsa_sign">Lỗi đăng ký với khóa lưu trữ Android %1$s: %2$s</string>
+ <string name="faq_system_dialogs">Các kết nối VPN đang cảnh báo bạn rằng ứng dụng này có thể chặn tất cả lưu lượng được đặt bởi hệ thống để chặn tình trạng lạm dụng VPN API. \nThông báo kết nối VPN (Biểu tượng chìa khóa) cũng được đặt bởi hệ thống Android để báo hiệu một kết nối VPN đang hoạt động. Với một số trường hợp thông báo này sẽ phát một âm thanh. \nAndroid giới thiệu những đoạn hội thoại này vì sự an toàn của bạn và chắn chắn rằng chúng không thể bị xâm nhập phá hoại. (Trên một số trường hợp thật không may không bao gồm âm thanh thông báo)</string>
+ <string name="faq_system_dialogs_title">Cảnh báo kết nối và thông báo âm thanh</string>
+ <string name="translationby">Phiên dịch tiếng Việt bởi Tojido Takarin&lt;tojidotakarin@gmail.com&gt;</string>
+ <string name="ipdns">IP và DNS</string>
+ <string name="basic">Cơ bản</string>
+ <string name="routing">Định tuyến</string>
+ <string name="obscure">Ẩn danh cài đặt OpenVPN. Bình thường việc này không cần thiết.</string>
+ <string name="advanced">Nâng cao</string>
+ <string name="export_config_title">Cấu hình ICS OpenVPN</string>
+ <string name="warn_no_dns">Không có máy chủ DNS đang sử dụng. Tên giải quyết có thể không hoạt động. Xem xét việc thiết lập máy chủ DNS. Cũng xin lưu ý rằng Android sẽ tiếp tục dùng cấu hình cài đặt proxy của bạn để kết nối cho điện thoại di động của bạn/kết nối Wifi khi không có máy chủ DNS được thiết lập.</string>
+ <string name="dns_add_error">Không thể thêm máy chủ DNS \"%1$s\", bị từ chối bởi hệ thống: %2$s</string>
+ <string name="ip_add_error">Không thể cấu hình địa chỉ IP \"%1$s\", từ chối bởi hệ thống: %2$s</string>
+ <string name="faq_howto">&lt;p&gt;Nhận cấu hình hoạt động (thử nghiệm trên máy tính hoặc tải về từ nhà cung cấp dịch vụ của bạn/hoặc tổ chức)&lt;/p&gt;&lt;p&gt;Nếu nó là một tập tin duy nhất mà không có tập tin pem/pks12 bạn có thể gửi email tập tin đó của bạn và mở tệp đính kèm. Nếu bạn có nhiều tập tin, hãy để nó trên thẻ nhớ của bạn&lt;/p&gt;&lt;p&gt;Nhấp vào tập tin đính kèm trên email /Dùng biểu tượng thư mục để nhập VPN mới vào danh sách VPN của bạn&lt;/p&gt;&lt;p&gt;Nếu có tập tin sai sót thì hãy để các tập tin lỗi đó trên thẻ nhớ của bạn&lt;/p&gt;&lt;p&gt;Nhấn vào biểu tượng Lưu để thêm VPN mới vào VPN của bạn&lt;/p&gt;&lt;p&gt;Kết nối VPN bằng cách nhấn vào tên của nó&lt;/p&gt;&lt;p&gt;Nếu có lỗi hoặc cảnh báp trong bản ghi đăng nhập thì hãy cố gắng tìm hiểu cảnh báo/ lỗi đó và cố thử sửa chúng&lt;/p&gt; </string>
+ <string name="faq_howto_title">Khởi động nhanh</string>
+ <string name="setting_loadtun_summary">Thử tải tun.ko module kernel trước khi kết nối. Cần phải root thiết bị.</string>
+ <string name="setting_loadtun">Tải tun module</string>
+ <string name="importpkcs12fromconfig">Nhập PKCS12 từ cấu hình vào Khóa lưu trữ Android</string>
+ <string name="getproxy_error">Lỗi nhận cấu hình proxy: %s</string>
+ <string name="using_proxy">Đang sử dụng proxy %1$s %2$d</string>
+ <string name="use_system_proxy">Sử dụng proxy hệ thống</string>
+ <string name="use_system_proxy_summary">Sử dụng các cấu hình hệ thống rộng cho HTTP/HTTPS proxy để kết nối.</string>
+ <string name="donatewithpaypal">Bạn có thể &lt;a href=\"https://www.paypal.com/cgi-bin/webscr?hosted_button_id=R2M6ZP9AF25LS&amp;amp;cmd=_s-xclick\"&gt;ủng hộ cho ứng dụng với PayPal&lt;/a&gt; </string>
+ <string name="onbootrestartsummary">OpenVPN sẽ kết nối lại VPN nếu nó đã hoạt động khi hệ thống khởi động lại/tắt máy. Xin vui lòng đọc phần cảnh báo kết nối trong các câu hỏi thường gặp trước khi sử dụng tùy chọn này.</string>
+ <string name="onbootrestart">Kết nối lại khi khởi động lại máy</string>
+ <string name="ignore">Bỏ qua</string>
+ <string name="restart">Khởi động lại</string>
+ <string name="restart_vpn_after_change">Cấu hình sẽ được áp dụng sau khi khởi động lại VPN. (Khởi động) bắt đầu VPN lại ngay bây giờ?</string>
+ <string name="configuration_changed">Cấu hình đã thay đổi</string>
+ <string name="log_no_last_vpn">Không thể xác định hồ sơ kết nối cuối cùng để chỉnh sửa</string>
+ <string name="faq_duplicate_notification_title">Thông báo trùng lặp</string>
+ <string name="faq_duplicate_notification">Nếu Android đang chịu ảnh hưởng của bộ nhớ hệ thống (RAM), các ứng dụng và dịch vụ không cần thiết sẽ được xóa khỏi bộ nhớ hoạt động. Điều này sẽ chấm dứt kết nối VPN. Để đảm bảo rằng kết nối/dịch vụ OpenVPN chạy với độ ưu tiên cao. Để chạy với độ ưu tiên cao hơn phải hiển thị một thông báo. Biểu tượng khóa thông báo đang được áp đặt bởi hệ thống như được mô tả trong các câu hỏi thường gặp trước. Nếu nó không được tính là thông báo ứng dụng cho mục đích chạy với độ ưu tiên cao.</string>
+ <string name="no_vpn_profiles_defined">Không có hồ sơ VPN được xác định.</string>
+ <string name="add_new_vpn_hint">Sử dụng &lt;img src=\"ic_menu_add\"/&gt; biểu tượng để thêm VPN mới</string>
+ <string name="vpn_import_hint">Sử dụng &lt;img src=\"ic_menu_archive\"/&gt; biểu tượng để nhập tập tin cấu hình hồ sơ (.ovpn hoặc .conf) từ thẻ nhớ của bạn.</string>
+ <string name="faq_hint">Hãy chắc chắn đã xem qua các câu hỏi thường gặp. Có một phần hướng dẫn bắt đầu nhanh.</string>
+ <string name="faq_routing_title">Định tuyến/giao diện cấu hình</string>
+ <string name="faq_routing">Định tuyến và cấu hình giao diện không được thực hiện thông qua lệnh ifconfig/dòng lệnh định tuyến nhưng được dùng bằng cấu hình VPN API. Điều này dẫn đến một cấu hình định tuyến khác hơn những hệ điều hành khác. \nCấu hình của đường truyền VPN bao gồm các địa chỉ IP và mạng lưới được định tuyến qua giao diện này. Đặc biệt, không có địa chỉ đối tác ngay hàng hoặc cổng địa chỉ cần thiết hoặc bắt buộc. Các định tuyến đặc biệt để kết nối đến máy chủ VPN (ví dụ thêm vào khi sử dụng cổng kết nối chuyển hướng) thì không cần thiết. Ứng dụng sẽ bỏ qua những cài đặt khi thiết lập cấu hình. Ứng dụng được gán với dịch vụ VPN API để kết nối đến máy chủ không được định tuyến thông qua VPN.\nCấu hình dịch vụ VPN API sẽ không cho phép các mạng mà không được định tuyến qua VPN. Như các ứng dụng cố gắng để xác lập mạng lưới sẽ không được định tuyến thông qua đường truyền (ví dụ định tuyến x.x.x.x y.y.y.y net_gateway) và tính toán xác định đường truyền để cạnh tranh với các nền tảng khác. Cửa sổ đăng nhập hiển thị cấu hình dịch vụ VPN khi thiết lập kết nối.\nSau đây: Android 4.4+ sẽ không dùng chính sách định tuyến nữa. Dùng định tuyến/ifconfig sẽ không hiển thị các định tuyến đã cài đặt. Thay vì sử dụng quy tắc ip, iptables -t mangle -L</string>
+ <string name="persisttun_summary">Đừng ngắt kết nối VPN khi OpenVPN đang kết nối lại.</string>
+ <string name="persistent_tun_title">Tun thường xuyên truy cập</string>
+ <string name="openvpn_log">Đăng nhập OpenVPN</string>
+ <string name="import_config">Nhập cấu hình OpenVPN</string>
+ <string name="battery_consumption_title">Mức tiêu thụ pin</string>
+ <string name="baterry_consumption">Trong các lần thử nghiệm của tôi thì lý do chính ở việc tiêu thụ pin cao của OpenVPN là do các gói dữ liệu trực tuyến liên tục. Hầu hết các máy chủ OpenVPN có một chỉ thị cấu hình như \'trực tuyến liên tục 10 60\' mà nguyên nhân của máy trạm và máy chủ trao đổi với nhau các gói dữ liệu trực tuyến này mỗi 10 giây. &lt;p&gt; Trong khi các gói dữ liệu nhỏ và không sử dụng nhiều lưu lượng truy cập. (Xem thêm &lt;a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\"&gt;The Radio State Machine | Nhà phát triển Android&lt;/a&gt;) &lt;p&gt; Gói dữ liệu trực tuyến này không thể thay đổi trên máy trạm. Chỉ quản trị viên hệ thống của OpenVPN mới có thể thay đổi. &lt;p&gt; Không may là nếu sử dụng các gói dữ liệu trực tuyến này hơn 60 giây với UDP có thể gây ra hiện tượng các cổng NAT thả các kết nối do chờ một thời gian mà không hoạt động. Sử dụng TCP với một thời gian dài không hoạt động, nhưng thông lượng TCP qua cấu hình TCP thực hiện rất kém trên kết nối với độ mất mát gói cao. (Xem &lt;a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\"&gt;Tại sao TCP qua TCP lại là một ý kiến tồi?&lt;/a&gt;)</string>
+ <string name="faq_tethering">Các tính năng Android Tethering (thông qua Wifi, USB hoặc Bluetooth) và các dịch vụ VPN API (được sử dụng bởi chương trình này) không làm việc cùng nhau. Để biết thêm chi tiết xin xem tại &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\"&gt;issue #34&lt;/a&gt;</string>
+ <string name="vpn_tethering_title">VPN và Tethering</string>
+ <string name="connection_retries">Thử lại kết nối</string>
+ <string name="reconnection_settings">Thiết lập kết nối lại</string>
+ <string name="connectretrymessage">Số giây đợi trong khi cố gắng kết nối.</string>
+ <string name="connectretrywait">Số giây giữa các kết nối</string>
+ <string name="minidump_generated">OpenVPN bất ngờ bị lỗi. Vui lòng xem xét và gửi tùy chọn Báo cáo sự cố trong menu chính</string>
+ <string name="send_minidump">Gửi Báo cáo lỗi đến nhà phát triển</string>
+ <string name="send_minidump_summary">Gửi thông tin gỡ lỗi về sự cố lần cuối đến nhà phát triển</string>
+ <string name="notifcation_title">OpenVPN - %s</string>
+ <string name="session_ipv4string">%1$s - %2$s</string>
+ <string name="session_ipv6string">%1$s - %3$s, %2$s</string>
+ <string name="state_connecting">Đang kết nối</string>
+ <string name="state_wait">Đang chờ máy chủ phản hồi</string>
+ <string name="state_auth">Đang chứng thực</string>
+ <string name="state_get_config">Đang nhận cấu hình máy trạm</string>
+ <string name="state_assign_ip">Đang gán các địa chỉ IP</string>
+ <string name="state_add_routes">Đang thêm các định tuyến</string>
+ <string name="state_connected">Đã kết nối</string>
+ <string name="state_disconnected">Đã ngắt kết nối</string>
+ <string name="state_reconnecting">Đang kết nối lại</string>
+ <string name="state_exiting">Đang thoát</string>
+ <string name="state_noprocess">Đang ngưng hoạt động</string>
+ <string name="state_resolve">Đang xử lý tên máy chủ lưu trữ</string>
+ <string name="state_tcp_connect">Đang kết nối (TCP)</string>
+ <string name="state_auth_failed">Chứng thực không thành công</string>
+ <string name="state_nonetwork">Đang đợi mạng khả dụng</string>
+ <string name="statusline_bytecount">↓%2$s/s %1$s - ↑%4$s/s %3$s</string>
+ <string name="notifcation_title_notconnect">Không kết nối</string>
+ <string name="start_vpn_title">Đang kết nối VPN %s</string>
+ <string name="start_vpn_ticker">Đang kết nối VPN %s</string>
+ <string name="jelly_keystore_alphanumeric_bug">Một số phiên bản Android 4.1 có vấn đề nếu tên của khóa lưu trữ chứng chỉ chứa các ký tự không phải chữ và số (như dấu cách, gạch chân hoặc gạch ngang). Hãy thử nhập lại chứng chỉ không có ký tự đặc biệt</string>
+ <string name="encryption_cipher">Mã hóa mật mã</string>
+ <string name="packet_auth">Gói xác thực</string>
+ <string name="auth_dialog_title">Nhập phương thức xác thực gói</string>
+ <string name="mobile_info_extended">Đang chạy trên %1$s (%2$s) %3$s, Android API %4$d, phiên bản %5$s, %6$s</string>
+ <string name="built_by">được xây dựng bởi %s</string>
+ <string name="debug_build">bản dựng gỡ lỗi</string>
+ <string name="official_build">bản dựng chính thức</string>
+ <string name="make_selection_inline">Sao chép vào hồ sơ</string>
+ <string name="crashdump">Báo cáo sự cố</string>
+ <string name="add">Thêm</string>
+ <string name="send_config">Gửi tập tin cấu hình</string>
+ <string name="complete_dn">Hoàn tất DN</string>
+ <string name="remotetlsnote">Cấu hình bạn nhập vào dùng tùy chọn DEPRECATED cũ, cấu hình tls từ xa khác với định dạng DN.</string>
+ <string name="rdn">RDN (tên thường gọi)</string>
+ <string name="rdn_prefix">Tiền tố RDN</string>
+ <string name="tls_remote_deprecated">tls-remote (DEPRECATED)</string>
+ <string name="help_translate">Bạn có thể giúp phiên dịch bằng cách truy cập http://crowdin.net/project/ics-openvpn/invite</string>
+ <string name="prompt">%1$s cố gắng để kiểm soát %2$s</string>
+ <string name="remote_warning">Hiện tại, bạn đang cho phép các ứng dụng có quyền kiểm soát OpenVPN cho Android và chặn tất cả lưu lượng mạng.<b>KHÔNG chấp nhận nếu bạn không tin tưởng ứng dụng này.</b>Nếu không, bạn có nguy cơ bị tổn hại dữ liệu bởi những phần mềm chứa mã độc.\"</string>
+ <string name="remote_trust">Tôi tin tưởng ứng dụng này.</string>
+ <string name="no_external_app_allowed">Không có ứng dụng cho phép sử dụng API bên ngoài</string>
+ <string name="allowed_apps">Cho phép ứng dụng: %s</string>
+ <string name="clearappsdialog">Xóa danh sách ứng dụng bên ngoài được cho phép?\nDanh sách hiện tại các ứng dụng được cho phép:\n\n%s</string>
+ <string name="screenoff_summary">\"Tạm dừng VPN khi màn hình tắt và truyền dữ liệu ít hơn 64KB trong 60 giây. Khi tùy chọn \"TUN thường dùng\" được kích hoạt sẽ tạm dừng các VPN để ứng dụng của bạn KHÔNG kết nối mạng. Nếu không chọn tùy chọn \"TUN thường dùng\" thì thiết bị sẽ không có kết nối VPN/hoặc bảo vệ.</string>
+ <string name="screenoff_title">Tạm dừng kết nối VPN sau khi tắt màn hình</string>
+ <string name="screenoff_pause">Tạm dừng kết nối khi màn hình tắt: ít hơn %1$s trong %2$s</string>
+ <string name="screen_nopersistenttun">Cảnh báo: TUN thường dùng không được bật cho VPN này. Lưu lượng sẽ dùng kết nối mạng bình thường khi màn hình tắt.</string>
+ <string name="save_password">Lưu mật khẩu</string>
+ <string name="pauseVPN">Tạm dừng VPN</string>
+ <string name="resumevpn">Tiếp tục VPN</string>
+ <string name="state_userpause">VPN tạm dừng theo yêu cầu của người dùng</string>
+ <string name="state_screenoff">VPN đã tạm dừng - tắt màn hình</string>
+ <string name="device_specific">Chi tiết thiết bị xâm nhập</string>
+ <string name="cannotparsecert">Không thể hiển thị thông tin chứng chỉ</string>
+ <string name="appbehaviour">Hành vi ứng dụng</string>
+ <string name="vpnbehaviour">Hành vi VPN</string>
+ <string name="allow_vpn_changes">Cho phép thay đổi Hồ sơ VPN</string>
+ <string name="hwkeychain">Khóa lưu trữ phần cứng:</string>
+ <string name="permission_icon_app">Biểu tượng của ứng dụng đang cố gắng sử dụng OpenVPN cho Android</string>
+ <string name="faq_vpndialog43">"Bắt đầu với Android 4.3, việc xác nhận VPN được hiểu như là xác nhận \"ứng dụng nền tảng\". Kết quả này trên hộp thoại không nhận việc nhập liệu vào. Nếu bạn tìm thấy ứng dụng sử dụng nền có thể gây ra vấn đề này, nó là vi phạm và hãy liên hệ với tác giả. Vấn đề này ảnh hưởng đến tất cả ứng dụng VPN trên Android 4.3 và cao hơn. Xem thêm &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\"&gt;Issue 185&lt;a&gt; để biết thêm chi tiết"</string>
+ <string name="faq_vpndialog43_title">Hộp thoại xác nhận VPN</string>
+ <string name="donatePlayStore">Ngoài ra, bạn có thể gửi tài trợ cho tôi bằng CH Play:</string>
+ <string name="thanks_for_donation">Cảm ơn bạn đã tài trợ %s!</string>
+ <string name="logCleared">Xóa Bản ghi.</string>
+ <string name="show_password">Hiển thị mật khẩu</string>
+ <string name="keyChainAccessError">Lỗi truy cập Keychain: %s</string>
+ <string name="timestamp_short">Ngắn</string>
+ <string name="timestamp_iso">ISO</string>
+ <string name="timestamps">Dấu thời gian</string>
+ <string name="timestamps_none">Không</string>
+ <string name="uploaded_data">Tải lên</string>
+ <string name="downloaded_data">Tải xuống</string>
+ <string name="vpn_status">Trạng thái VPN</string>
+ <string name="logview_options">Xem tùy chọn</string>
+ <string name="unhandled_exception">Tùy chọn ngoại lệ: %1$s\n\n%2$s</string>
+ <string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
+ <string name="faq_system_dialog_xposed">Nếu bạn đã root thiết bị Android bạn có thể cài đặt &lt;href=\"http://xposed.info/\"&gt;Xposed framework&lt;/a&gt; và &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;Hộp thoại xác nhận VPN module&lt;/a&gt; để xác nhận nguy cơ\"</string>
+ <string name="full_licenses">Giấy phép đầy đủ</string>
+ <string name="blocklocal_summary">Mạng kết nối trực tiếp đến giao diện địa phương sẽ không định tuyến qua VPN. Bỏ tùy chọn này sẽ chuyển hướng tất cả lưu lượng truy cập cho mạng nội bộ đến VPN.</string>
+ <string name="blocklocal_title">Bỏ qua VPN cho mạng địa phương</string>
+ <string name="userpw_file">Tập tin tên người dùng/Mật khẩu</string>
+ <string name="imported_from_file">[Nhập khẩu từ: %s]</string>
+ <string name="files_missing_hint">Một số tập tin không thể tìm thấy. Vui lòng chọn tập tin để nhập vào hồ sơ:</string>
+ <string name="openvpn_is_no_free_vpn">Để dùng ứng dụng này bạn cần một nhà cung cấp dịch vụ VPN/ cổng hỗ trợ OpenVPN (thường được cung cấp bởi chủ sở hữu). Kiểm tra tại http://community.openvpn.net/ để biết thêm thông tin về Open VPN và cách làm thế nào để thiết lập máy chủ Open VPN của riêng bạn.</string>
+ <string name="import_log">Nhập bản ghi:</string>
+ <string name="ip_looks_like_subnet">Cấu trúc VPN \"%3$s\" quy định nhưng ifconfig %1$s %2$s trông giống như một địa chỉ IP với một mặt nạ mạng. Giả định cấu trúc liên kết \"mạng con\".</string>
+ <string name="mssfix_invalid_value">Các giá trị MSS phải là một số nguyên từ 0 đến 9000</string>
+ <string name="mssfix_value_dialog">Thông báo với các phiên TCP đang chạy thông qua đường truyền mà chúng nên hạn chế gửi kích cỡ gói dữ liệu sau khi Open VPN đã đóng gói nó, kết quả kích thước gói dữ liệu UDP mà OpenVPN gửi tới sẽ không vượt qua số byte này. (Mặc định là 1450)</string>
+ <string name="mssfix_checkbox">Ghi đè lên giá trị MSS của TCP payload</string>
+ <string name="mssfix_dialogtitle">Đặt MSS của TCP payload</string>
+ <string name="client_behaviour">Hành vi máy trạm</string>
+ <string name="clear_external_apps">Xóa các ứng dụng bên ngoài đã cho phép</string>
+ <string name="loading">Đang tải...</string>
+ <string name="allowed_vpn_apps_info">Cho phép các ứng dụng VPN: %1$s</string>
+ <string name="disallowed_vpn_apps_info">Không cho phép ứng dụng VPN: %1$s</string>
+ <string name="app_no_longer_exists">Gói %s không còn được cài đặt nữa, gỡ bỏ nó từ danh sách ứng dụng cho phép/không cho phép</string>
+ <string name="vpn_disallow_radio">VPN được sử dụng cho tất cả các ứng dụng nhưng loại trừ lựa chọn này</string>
+ <string name="vpn_allow_radio">VPN được dùng chỉ cho các ứng dụng được lựa chọn</string>
+ <string name="query_delete_remote">Gỡ bỏ mục nhập máy chủ từ xa?</string>
+ <string name="keep">Giữ</string>
+ <string name="delete">Xóa</string>
+ <string name="add_remote">Thêm điều khiển từ xa mới</string>
+ <string name="remote_random">Sử dụng mục kết nối ngẫu nhiên</string>
+ <string name="remote_no_server_selected">Bạn cần phải xác định và cho phép ít nhất một máy chủ từ xa.</string>
+ <string name="server_list">Danh sách máy chủ</string>
+ <string name="vpn_allowed_apps">Cho phép ứng dụng</string>
+ <string name="advanced_settings">Cài đặt nâng cao</string>
+ <string name="payload_options">Tùy chọn Payload</string>
+ <string name="tls_settings">Cài đặt TLS</string>
+ <string name="no_remote_defined">Không xác định điều khiển từ xa</string>
+ <string name="duplicate_vpn">Hồ sơ VPN trùng lặp</string>
+ <string name="duplicate_profile_title">Sao chép hồ sơ: %s</string>
+ <string name="show_log">Hiển thị đăng nhập</string>
+ <string name="faq_android_clients">Nhiều máy trạm OpenVPN cho Android đang tồn tại. Việc phổ biến nhất là OpenVPN cho Android (client này), OpenVPN Connect và OpenVPN Settings &lt;p&gt; Các khách hàng có thể được chia thành hai nhóm: OpenVPN cho Android và OpenVPN Connect sử dụng dịch vụ VPN API chính thức (Android 4.0 +) không cần quyền root và Open VPN khi dùng root. &lt;p&gt; OpenVPN cho Android là ứng dụng mã nguồn mở và phát triển bởi Arne Schwabe. Mục tiêu hàng đầu cho những người dùng cao cấp hơn và khả năng nhập hồ sơ từ các tập tin cấu hình/thay đổi hồ sơ bên trong ứng dụng. Các khách hàng được dựa trên phiên bản cộng đồng của OpenVPN. Nó được dựa trên mã nguồn 2.x OpenVPN. Máy trạm này có thể được xem như là máy trạm chính thức của cộng đồng. &lt;p&gt; OpenVPN Connect là máy trạm mã nguồn mở được phát triển bởi OpenVPN Technologies, Inc. Các khách hàng có thể dùng chung với nhiều mục tiêu vì chúng tôi nhắm vào người dùng bình thường và cho phép nhập khẩu hồ sơ OpenVPN. Máy trạm dựa trên OpenVPN C ++ reimplementation của giao thức OpenVPN (Điều này đã được yêu cầu để cho phép OpenVPN Technologies, Inc xuất bản một ứng dụng iOS OpenVPN).Máy trạm này là chính thức của công nghệ OpenVPN &lt;p&gt; OpenVPN Setting là máy trạm lâu đời nhất và cũng là UI cho mã nguồn mở OpenVPN. Ngược lại, OpenVPN cho Android yêu cầu quyền root và không sử dụng dịch vụ VPN API. Nó không xây dựng phụ thuộc cho Android 4.0+</string>
+ <string name="faq_androids_clients_title">Sự khác nhau giữa các máy trạm OpenVPN Android</string>
+ <string name="ignore_multicast_route">Bỏ qua định tuyến đa luồng: %s</string>
+ <string name="ab_only_cidr">Android chỉ hỗ trợ định tuyến CIDR cho VPN. Kể từ khi định tuyến không phải CIDR hầu như không dùng nữa, OpenVPN cho Android sẽ sử dụng một định tuyến /32 mà không phải là CIDR và cảnh báo sự cố.</string>
+ <string name="ab_tethering_44">Tethering hoạt động trong khi VPN đang kích hoạt. Các kết nối Tetherd sẽ KHÔNG sử dụng VPN.</string>
+ <string name="ab_kitkat_mss">Các phiên bản trước KitKat thiết lập giá trị MSS trên kết nối TCP (#61948). OpenVPN sẽ tự động kích hoạt tùy chỉnh mssfix để xử lý lỗi này.</string>
+ <string name="ab_proxy">Android sẽ sử dụng cấu hình proxy của bạn để kết nối điện thoại/Wifi khi không có máy chủ DNS được đặt. OpenVPN cho Android sẽ cảnh báo bạn về điều này trong bản ghi.<p>Khi VPN thiết đặt máy chủ DNS Android sẽ không kèm proxy. Không có API nào thiết đặt cho proxy trong kết nối VPN.</p></string>
+ <string name="ab_lollipop_reinstall">Ứng dụng VPN có thể dừng hoạt động khi gỡ cài đặt và cài đặt lại lần nữa. Chi tiết xem tại #80074</string>
+ <string name="ab_not_route_to_vpn">Cấu hình IP của máy trạm và IP trong mặt nạ mạng thì không định tuyến đến VPN. OpenVPN hoạt động bởi sự cố này bằng cách thêm định tuyến mà chuyển đến địa chỉ IP máy trạm và mặt nạ mạng của nó</string>
+ <string name="ab_persist_tun">Mở một thiết bị tun khi một thiết bị tun khác đang hoạt động, có thể dùng để hỗ trợ tun, sự cố trên dịch vụ VPN. Cần khởi động lại để VPN hoạt động. OpenVPN cho Android cố gắng mở lại thiết bị tun và thực sự cần thiết để đóng TUN hiện tại trước khi mở TUN mới để tránh sự cố. Điều này có thể dẫn đến một cửa sổ nơi các gói tin được gửi qua kết nối không dây VPN. Ngay cả việc giải quyết dịch vụ VPN này thỉnh thoảng vẫn gặp sự cố và cần phải khởi động lại thiết bị.</string>
+ <string name="ab_secondary_users">VPN không làm việc cho tất cả người dùng phổ thông.</string>
+ <string name="ab_kitkat_reconnect">"Nhiều người dùng báo cáo rằng kết nối của di động/dữ liệu di động thỉnh thoảng bị gián đoạn trong khi sử dụng VPN. Các lỗi này dường như chỉ ảnh hưởng bởi một số nhà cung cấp dịch vụ di động/bản chất của thiết bị và cho đến nay chưa xác định được nguyên nhân gây lỗi."</string>
+ <string name="ab_vpn_reachability_44">Chỉ có nguồn đích mới có thể truy cập vượt qua VPN mà không cần VPN. IPv6 không hoạt động cho tất cả.</string>
+ <string name="ab_only_cidr_title">Không định tuyến CIDR</string>
+ <string name="ab_proxy_title">Proxy chuyển tiếp cho VPN</string>
+ <string name="ab_lollipop_reinstall_title">Đang cài đặt lại ứng dụng VPN</string>
+ <string name="version_upto">%s và trước đó</string>
+ <string name="copy_of_profile">Bản sao của %s</string>
+ <string name="ab_not_route_to_vpn_title">Định tuyến đến cấu hình địa chỉ IP</string>
+ <string name="ab_kitkat_mss_title">Giá trị MSS sai cho kết nối VPN</string>
+ <string name="ab_secondary_users_title">Người sử dụng máy tính bảng thứ cấp</string>
+ <string name="custom_connection_options_warng">Xác định kết nối tùy chỉnh cụ thể. Dùng cẩn thận</string>
+ <string name="custom_connection_options">Cấu hình tùy chỉnh</string>
+ <string name="remove_connection_entry">Gỡ bỏ mục kết nối</string>
+</resources>
diff --git a/app/src/main/res/values-zh-rCN/strings-icsopenvpn.xml b/app/src/main/res/values-zh-rCN/strings-icsopenvpn.xml
index 4a3da0f4..01fa64a2 100755
--- a/app/src/main/res/values-zh-rCN/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-zh-rCN/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">服务器地址:</string>
@@ -14,8 +12,8 @@
<string name="cant_read_folder">无法读取目录</string>
<string name="select">选择</string>
<string name="cancel">取消</string>
- <string name="no_data">无数据</string>
- <string name="useLZO">LZO 压缩</string>
+ <string name="no_data">未收到数据</string>
+ <string name="useLZO">启用 LZO 压缩算法</string>
<string name="client_no_certificate">无客户端证书</string>
<string name="client_certificate_title">客户端证书</string>
<string name="client_key_title">客户端证书密钥</string>
@@ -36,7 +34,7 @@
<string name="ipv4_dialog_title">输入 CIDR 格式 IPv4 地址/子网掩码(例如:1.2.3.4/24)</string>
<string name="ipv4_address">IPv4 地址</string>
<string name="ipv6_address">IPv6 地址</string>
- <string name="custom_option_warning">请谨慎输入 OpenVPN 的自定义选项。此外请注意许多与 tun 模块有关的 OpenVPN 设置由于系统 VPN 功能的设计而不能得到支持。如果您缺少认为一个很重要的选项,请联系作者。</string>
+ <string name="custom_option_warning">请谨慎输入 OpenVPN 的自定义选项。此外请注意许多与 tun 模块有关的 OpenVPN 设置由于系统 VPN 功能的设计而不能得到支持。如果您觉得缺少一个很重要的选项,请与作者联系。</string>
<string name="auth_username">用户名</string>
<string name="auth_pwquery">密码</string>
<string name="static_keys_info">静态配置中 TLS 身份验证密钥将被用作静态密钥</string>
@@ -51,7 +49,7 @@
<string name="ipv4_format_error">无法解析 IPv4 地址</string>
<string name="custom_route_format_error">无法解析自定义路由</string>
<string name="pw_query_hint">(根据需求留空)</string>
- <string name="vpn_shortcut">OpenVPN 快捷方式</string>
+ <string name="vpn_shortcut">OpenVPN 主屏幕快捷方式</string>
<string name="vpn_launch_title">连接至 VPN</string>
<string name="shortcut_profile_notfound">未找到快捷方式中指定的配置文件</string>
<string name="random_host_prefix">随机主机前缀</string>
@@ -65,7 +63,7 @@
<string name="title_cancel">取消确认</string>
<string name="cancel_connection_query">断开已连接的 VPN / 取消连接尝试?</string>
<string name="remove_vpn">删除 VPN</string>
- <string name="check_remote_tlscert">检查服务器是否使用了 TLS服务器端扩展 (--remote-cert-tlsserver server)</string>
+ <string name="check_remote_tlscert">检查服务器是否使用 TLS 服务器端扩展 (--remote-cert-tlsserver server)</string>
<string name="check_remote_tlscert_title">需要 TLS 服务器证书</string>
<string name="remote_tlscn_check_summary">检查远程服务器证书的 DN 属性</string>
<string name="remote_tlscn_check_title">证书主机名检查</string>
@@ -145,7 +143,7 @@
<string name="add_profile">添加配置文件</string>
<string name="import_could_not_open">无法找到导入配置文件参考的文件: %1$s</string>
<string name="importing_config">从 %1$s 中导入配置文件</string>
- <string name="import_warning_custom_options">您的配置文件中有几个配置项无法在配置菜单中查看和修改,这些配置项将会当成自定义配置选项。下面是自定义的配置选项:</string>
+ <string name="import_warning_custom_options">您的配置文件中有几个配置项无法在配置菜单中查看和修改,这些配置项将会当成自定义配置选项。下面是这些自定义的配置选项:</string>
<string name="import_done">读取配置文件完成</string>
<string name="nobind_summary">不关联到本地地址和端口</string>
<string name="no_bind">无本地绑定</string>
@@ -228,6 +226,7 @@
<string name="openvpn_log">OpenVPN 日志</string>
<string name="import_config">导入 OpenVPN 配置文件</string>
<string name="battery_consumption_title">电池消耗</string>
+ <string name="baterry_consumption">在我的测试中,发现最能消耗电量的是 OpenVPN 的 keepalive 包。大多数 OpenVPN 服务器都在配置文件中使用了“keepalive 10 60”这样的选项,这会导致 OpenVPN 服务器和客户端每隔 10 秒就相互向对方发送一个数据包。&lt;p&gt;虽然这些包很小,几乎不会消耗多少流量,但是频繁地发送这些包会导致手机的无线模块长时间处于活跃状态,并消耗大量的电能。(请参见(英文网页): &lt;a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\"&gt;)&lt;p&gt; keepalive 选项无法在客户端进行修改,只能在服务器上进行修改。&lt;p&gt;令人郁闷的是,如果发送 keepalive 的频率小于 60 秒,某些 NAT 网关可能会关闭 UDP 连接(我测试得到的结果是 60 秒)。使用 TCP 模式虽然可以将 keepalive 的频率设成很大,但是会造成 TCP over TCP 问题。(请参见(英文网页):&lt;a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\"&gt;)(TCP over TCP 问题指的是由于 TCP 协议的机制,在 TCP 协议上再次封装一个 TCP 协议时,如果上层 TCP 链路的速度比下层 TCP 协议的链路速度快,就会造成大量 TCP 重传,从而导致网络拥塞,对用户来说就是网络变成龟速 ——译者注)</string>
<string name="faq_tethering">Android 网络分享和便携式热点功能(通过 WiFi, USB 或蓝牙)无法与本程序所使用的 VPN 服务接口一同工作。详情请见 &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\"&gt;issue #34&lt;/a&gt;</string>
<string name="vpn_tethering_title">VPN 和中继</string>
<string name="connection_retries">连接重试次数</string>
@@ -278,6 +277,7 @@
<string name="tls_remote_deprecated">tls-remote(不再使用)</string>
<string name="help_translate">你可以通过访问 http://crowdin.net/project/ics-openvpn/invite 来帮助翻译</string>
<string name="prompt">%1$s 正在试图控制 %2$s</string>
+ <string name="remote_warning">如果继续,你将允许该应用完全控制 OpenVPN for Android,并拦截所有网络流量。<b>除非你信任该应用,否则请不要继续。</b>如果该应用是恶意应用,你需要自行承担所有的后果。</string>
<string name="remote_trust">我信任此应用。</string>
<string name="no_external_app_allowed">没有允许使用外部 API 的应用</string>
<string name="allowed_apps">已授权的应用:%s</string>
@@ -297,6 +297,10 @@
<string name="vpnbehaviour">VPN 行为</string>
<string name="allow_vpn_changes">允许更改 VPN 配置</string>
<string name="hwkeychain">硬件密钥库:</string>
+ <string name="permission_icon_app">应用程序试图使用 OpenVPN 为 Android 的图标</string>
+ <string name="faq_vpndialog43">"入手 Android 4.3 VPN 确认被防范\"覆盖应用程序\"。这将导致在不发生反应,触摸输入的对话框中。如果您有一个应用程序,使用覆盖它可能会导致这种行为。如果你发现违规应用程序联系的应用程序的作者。这个问题影响到所有 VPN 应用程序的 Android 4.3 及更高版本。请参阅 &lt; href =\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\"&gt; 问题 185 &lt; &gt; 有关其他详细信息"</string>
+ <string name="faq_vpndialog43_title">Vpn 确认对话框的 Android 4.3 及更高版本</string>
+ <string name="donatePlayStore">或者你可以给我捐赠与播放存储:</string>
<string name="thanks_for_donation">感谢捐赠 %s!</string>
<string name="logCleared">日志已清除。</string>
<string name="show_password">显示密码</string>
@@ -313,7 +317,50 @@
<string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
<string name="faq_system_dialog_xposed">如果您的 Android 设备已经 root,您可以自担风险安装&lt;a href=\"http://xposed.info/\"&gt;Xposed 框架&lt;/a&gt; 和 &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;VPN 对话框确认模块&lt;/a&gt;</string>
<string name="full_licenses">完整授权</string>
+ <string name="blocklocal_summary">不会将网络直接连接到本地接口路由通过 VPN。取消选中此选项会将缩进到 VPN 的本地网络的所有流量重都定向。</string>
<string name="blocklocal_title">对本地地址绕过 VPN</string>
<string name="userpw_file">用户名/密码文件</string>
+ <string name="imported_from_file">[从进口: %s]</string>
+ <string name="files_missing_hint">找不到一些文件。请选择要导入的配置文件的文件:</string>
+ <string name="openvpn_is_no_free_vpn">若要使用此应用程序需要支持 OpenVPN (通常由您的雇主提供) 的 VPN 提供商/VPN 网关。查阅 http://community.openvpn.net/ OpenVPN 和如何设置您自己的 OpenVPN 服务器的详细信息。</string>
<string name="import_log">导入日志:</string>
+ <string name="ip_looks_like_subnet">VPN拓扑“%3$s”指定的,但使用ifconfig %1$s %2$s看起来更像是一个网络掩码的IP地址。假设“子网”的拓扑结构。</string>
+ <string name="mssfix_invalid_value">mssfix 值必须是一个介于 0 和 9000 之间的整数</string>
+ <string name="mssfix_value_dialog">公布于运行在他们应该限制其发送分组大小,使得后的OpenVPN已包封它们,将得到的UDP包大小的OpenVPN发送到其对等体将不超过此字节数隧道TCP会话。 (默认为1450)</string>
+ <string name="mssfix_checkbox">重写TCP有效载荷的MSS值</string>
+ <string name="mssfix_dialogtitle">设置的 TCP MSS 负载</string>
+ <string name="client_behaviour">客户端行为</string>
+ <string name="clear_external_apps">明确允许外部应用程序</string>
+ <string name="loading">加载中...</string>
+ <string name="allowed_vpn_apps_info">允许 VPN 应用程序: %1$s</string>
+ <string name="disallowed_vpn_apps_info">不允许VPN应用:%1$s</string>
+ <string name="app_no_longer_exists">从应用程序允许禁止列表中移除它,不再安装包 %s</string>
+ <string name="vpn_disallow_radio">VPN 用于所有的应用程序,但排除选定</string>
+ <string name="vpn_allow_radio">VPN 是只用于所选的应用程序</string>
+ <string name="query_delete_remote">删除远程服务器的条目吗?</string>
+ <string name="keep">Thorny</string>
+ <string name="delete">删除</string>
+ <string name="add_remote">添加新的远程服务器</string>
+ <string name="remote_random">连接时随机选择配置文件</string>
+ <string name="remote_no_server_selected">您需要至少定义并启用一个远程服务器。</string>
+ <string name="server_list">服务器列表</string>
+ <string name="vpn_allowed_apps">允许的应用程序</string>
+ <string name="advanced_settings">高级选项</string>
+ <string name="payload_options">负载设置</string>
+ <string name="tls_settings">TLS 设置</string>
+ <string name="no_remote_defined">未定义任何远程服务器</string>
+ <string name="duplicate_vpn">重复的VPN配置文件</string>
+ <string name="duplicate_profile_title">创建配置文件副本: %s</string>
+ <string name="show_log">显示日志</string>
+ <string name="faq_android_clients">OpenVPN 的 Android 客户端目前市面上已经有了一些了,其中最常见的有 OpenVPN for Android(也就本应用)、OpenVPN Connect 以及 OpenVPN Settings 。
+这些客户端可以被分为两类:使用官方VPNService API (Android 4.0+) 并且不需要 root 权限的 OpenVPN for Android 和 OpenVPN Connect 以及需要 root 权限的 OpenVPN Settings 。</string>
+ <string name="faq_androids_clients_title">不同OpenVPN安卓客户端的区别</string>
+ <string name="ignore_multicast_route">忽略多播路由:%s</string>
+ <string name="ab_only_cidr">安卓只支持CIDR路由。由于非CIDR路由几乎不用,OpenVPN for Android将使用/32路由并对非CIDR路由发出警告。</string>
+ <string name="ab_tethering_44">在连接VPN时手机热点依然工作,但连接不会通过VPN。</string>
+ <string name="ab_kitkat_mss">早期的KitKat版本在TCP连接上设置了错误的MSS值 (#61948)。OpenVPN将自动启动mssfix选项来解决这个Bug。</string>
+ <string name="ab_only_cidr_title">非CIDR路由</string>
+ <string name="ab_lollipop_reinstall_title">正在重新安装VPN应用</string>
+ <string name="custom_connection_options">自定义选项</string>
+ <string name="remove_connection_entry">删除连接条目</string>
</resources>
diff --git a/app/src/main/res/values-zh-rTW/strings-icsopenvpn.xml b/app/src/main/res/values-zh-rTW/strings-icsopenvpn.xml
index 36360cf1..b0056965 100755
--- a/app/src/main/res/values-zh-rTW/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-zh-rTW/strings-icsopenvpn.xml
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
<!--
~ Copyright (c) 2012-2014 Arne Schwabe
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
-->
-
-<!--Generated by crowdin.com-->
-<!-- Generated by crowdin.net -->
<resources>
<string name="address">伺服器地址:</string>
diff --git a/app/src/main/res/values/refs.xml b/app/src/main/res/values/refs.xml
index 4d97e380..6abfb609 100644
--- a/app/src/main/res/values/refs.xml
+++ b/app/src/main/res/values/refs.xml
@@ -5,10 +5,10 @@
-->
<resources>
- <drawable name="ic_menu_close_clear_cancel">@android:drawable/ic_menu_close_clear_cancel</drawable>
- <drawable name="ic_menu_share">@android:drawable/ic_menu_share </drawable>
- <drawable name="ic_menu_save">@android:drawable/ic_menu_save</drawable>
- <drawable name="ic_menu_view">@android:drawable/ic_menu_view</drawable>
- <drawable name="ic_menu_delete">@android:drawable/ic_menu_delete</drawable>
- <drawable name="ic_menu_edit">@android:drawable/ic_menu_edit</drawable>
+ <drawable name="ic_menu_close_clear_cancel">@android:drawable/ic_menu_close_clear_cancel</drawable>
+ <drawable name="ic_menu_share">@android:drawable/ic_menu_share </drawable>
+ <drawable name="ic_menu_save">@android:drawable/ic_menu_save</drawable>
+ <drawable name="ic_menu_view">@android:drawable/ic_menu_view</drawable>
+ <drawable name="ic_menu_delete">@android:drawable/ic_menu_delete</drawable>
+ <drawable name="ic_menu_edit">@android:drawable/ic_menu_edit</drawable>
</resources>
diff --git a/app/src/main/res/values/strings-icsopenvpn.xml b/app/src/main/res/values/strings-icsopenvpn.xml
index 39ad1193..dec656fc 100755
--- a/app/src/main/res/values/strings-icsopenvpn.xml
+++ b/app/src/main/res/values/strings-icsopenvpn.xml
@@ -18,7 +18,7 @@
<string name="client_pkcs12_title">PKCS12 File</string>
<string name="ca_title">CA Certificate</string>
<string name="no_certificate">You must select a certificate</string>
- <string name="copyright_guicode">Source code and issue tracker available at http://code.google.com/p/ics-openvpn/</string>
+ <string name="copyright_guicode">Source code and issue tracker available at https://github.com/schwabe/ics-openvpn</string>
<string name="copyright_others">This program uses the following components; see the source code for full details on the licenses</string>
<string name="about">About</string>
<string name="vpn_list_title">Profiles</string>
@@ -294,8 +294,8 @@
<string name="allow_vpn_changes">Allow changes to VPN Profiles</string>
<string name="hwkeychain">Hardware Keystore:</string>
<string name="permission_icon_app">Icon of app trying to use OpenVPN for Android</string>
- <string name="faq_vpndialog43">"Starting with Android 4.3 the VPN confirmation is guarded against \"overlaying apps\". This results in the dialog not reacting to touch input. If you have an app that uses overlays it may cause this behaviour. If you find an offending app contact the author of the app. This problem affect all VPN applications on Android 4.3 and later. See also &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=185\">Issue 185&lt;a> for additional details"</string>
- <string name="faq_vpndialog43_title">Vpn Confirm Dialog on Android 4.3 and later</string>
+ <string name="faq_vpndialog43">"Starting with Android 4.3 the VPN confirmation is guarded against \"overlaying apps\". This results in the dialog not reacting to touch input. If you have an app that uses overlays it may cause this behaviour. If you find an offending app contact the author of the app. This problem affect all VPN applications on Android 4.3 and later. See also &lt;a href=\"https://github.com/schwabe/ics-openvpn/issues/185\">Issue 185&lt;a> for additional details"</string>
+ <string name="faq_vpndialog43_title">Vpn Confirmation Dialog</string>
<string name="donatePlayStore">Alternatively you can send me a donation with the Play Store:</string>
<string name="thanks_for_donation">Thanks for donating %s!</string>
<string name="logCleared">Log cleared.</string>
@@ -351,5 +351,36 @@
<string name="faq_android_clients">Multiple OpenVPN clients for Android exist. The most common ones are OpenVPN for Android (this client), OpenVPN Connect and OpenVPN Settings.&lt;p&gt;The clients can be grouped into two groups: OpenVPN for Android and OpenVPN Connect use the official VPNService API (Android 4.0+) and require no root and OpenVPN Settings which uses root.&lt;p&gt;OpenVPN for Android is an open source client and developed by Arne Schwabe. It is targeted at more advanced users and offers many settings and the ability to import profiles from files and to configure/change profiles inside the app. The client is based on the community version of OpenVPN. It is based on the OpenVPN 2.x source code. This client can be seen as the semi officially client of the community. &lt;p&gt;OpenVPN Connect is non open source client that is developed by OpenVPN Technologies, Inc. The client is indented to be general use client and moree targeted at the average user and allows the import of OpenVPN profiles. This client is based on the OpenVPN C++ reimplementation of the OpenVPN protocol (This was required to allow OpenVPN Technologies, Inc to publish an iOS OpenVPN app). This client is the official client of the OpenVPN technologies &lt;p&gt; OpenVPN Settings is the oldest of the clients and also a UI for the open source OpenVPN. In contrast to OpenVPN for Android it requires root and does not use the VPNService API. It does not depend on Android 4.0+</string>
<string name="faq_androids_clients_title">Differences between the OpenVPN Android clients</string>
<string name="ignore_multicast_route">Ignoring multicast route: %s</string>
+ <string name="ab_only_cidr">Android supports only CIDR routes to the VPN. Since non-CIDR routes are almost never used, OpenVPN for Android will use a /32 for routes that are not CIDR and issue a warning.</string>
+ <string name="ab_tethering_44">Tethering works while the VPN is active. The tethered connection will NOT use the VPN.</string>
+ <string name="ab_kitkat_mss">Early KitKat version set the wrong MSS value on TCP connections (#61948). Try to enable the mssfix option to workaround this bug.</string>
+ <string name="ab_proxy">Android will keep using your proxy settings specified for the mobile/Wi-Fi connection when no DNS servers are set. OpenVPN for Android will warn you about this in the log.<p>When a VPN sets a DNS server Android will not a proxy. There is no API to set a proxy for a VPN connection.</p></string>
+ <string name="ab_lollipop_reinstall">VPN apps may stop working when uninstalled and reinstalled again. For details see #80074</string>
+ <string name="ab_not_route_to_vpn">The configured client IP and the IPs in its network mask are not routed to the VPN. OpenVPN works around this bug by explicitly adding a route that corrosponds to the client IP and its netmask</string>
+ <string name="ab_persist_tun">Opening a tun device while another tun device is active, which is used for persist-tun support, crashes the VPNServices on the device. A reboot is required to make VPN work again. OpenVPN for Android tries to avoid reopening the tun device and if really needed first closes the current TUN before opening the new TUN device to avoid to crash. This may lead to a short window where packets are sent over the non-VPN connection. Even with this workaround the VPNServices sometimes crashes and requires a reboot of the device.</string>
+ <string name="ab_secondary_users">VPN does not work at all for secondary users.</string>
+ <string name="ab_kitkat_reconnect">"Multiple users report that the mobile connection/mobile data connection is frequently dropped while using the VPN app. The behaviour seems to affect only some mobile provider/device combination and so far no cause/workaround for the bug could be identified. "</string>
+ <string name="ab_vpn_reachability_44">Only destination can be reached over the VPN that are reachable without VPN. IPv6 VPNs does not work at all.</string>
+ <string name="ab_only_cidr_title">Non CIDR Routes</string>
+ <string name="ab_proxy_title">Proxy behaviour for VPNs</string>
+ <string name="ab_lollipop_reinstall_title">Reinstalling VPN apps</string>
+ <string name="version_upto">%s and earlier</string>
+ <string name="copy_of_profile">Copy of %s</string>
+ <string name="ab_not_route_to_vpn_title">Route to the configured IP address</string>
+ <string name="ab_kitkat_mss_title">Wrong MSS value for VPN connection</string>
+ <string name="ab_secondary_users_title">Secondary tablet users</string>
+ <string name="custom_connection_options_warng">Specify custom connection specific options. Use with care</string>
+ <string name="custom_connection_options">Custom Options</string>
+ <string name="remove_connection_entry">Remove connection entry</string>
+ <string name="ab_kitkat_reconnect_title">Random disconnects from mobile network</string>
+ <string name="ab_vpn_reachability_44_title">Remote networks not reachable</string>
+ <string name="ab_persist_tun_title">Persist tun mode</string>
+ <string name="version_and_later">%s and later</string>
+ <string name="tls_cipher_alert_title">Connections fails with SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure</string>
+ <string name="tls_cipher_alert">Newer OpenVPN for Android versions (0.6.29/March 2015) use a more secure default for the allowed cipher suites (tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\"). Unfortunately, omitting the less secure cipher suites and export cipher suites, especially the omission of cipher suites that do not support Perfect Forward Secrecy (Diffie-Hellman) causes some problems. This usually caused by an well-intentioned but poorly executed attempts to strengthen TLS security by setting tls-cipher on the server or some embedded OSes with stripped down SSL (e.g. MikroTik).\nTo solve this problem the problem, set the tls-cipher settings on the server to reasonable default like tls-cipher \"DEFAULT:!EXP:!PSK:!SRP:!kRSA\". To work around the problem on the client add the custom option tls-cipher DEFAULT on the Android client.</string>
+ <string name="message_no_user_edit">This profile has been added from an external app (%s) and has been marked as not user editable.</string>
+ <string name="crl_file">Certificate Revocation List</string>
+ <string name="service_restarted">Restarting OpenVPN Service (App crashed probably crashed or killed for memory pressure)</string>
+ <string name="import_config_error">Importing the config yielded an error, cannot save it</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d1e33928..7746795e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -16,7 +16,7 @@
<string name="provider_label">Provider:</string>
<string name="provider_label_none">No provider configured</string>
<string name="status_unknown">Status unknown.</string>
- <string name="eip_service_label">Encrypted Internet</string>
+ <string name="eip_service_label">VPN Encrypted Internet Access</string>
<string name="configuration_wizard_title">Select a service provider</string>
<string name="new_provider_button">Add new Provider</string>
<string name="introduce_new_provider">Add a new service provider</string>
@@ -47,6 +47,7 @@
<string name="setup_error_close_button">Exit</string>
<string name="setup_error_text">There was an error configuring Bitmask with your chosen provider.\n\nYou may choose to reconfigure, or exit and configure a provider upon next launch.</string>
<string name="server_unreachable_message">Server is unreachable, please try again.</string>
+ <string name="error.security.pinnedcertificate">Security error, update the app or choose another provider.</string>
<string name="malformed_url">It doesn\'t seem to be a Bitmask provider.</string>
<string name="certificate_error">This is not a trusted Bitmask provider.</string>
<string name="service_is_down_error">Service is down.</string>
@@ -54,11 +55,6 @@
<string name="incorrectly_downloaded_certificate_message">Your anon cert was not downloaded</string>
<string name="downloading_certificate_message">Downloading VPN certificate</string>
<string name="updating_certificate_message">Updating VPN certificate</string>
- <string name="authenticating_message">Logging in</string>
- <string name="signingup_message">Signing up</string>
- <string name="logout_message">Logging out from this session.</string>
- <string name="logged_out_message">Logged out.</string>
- <string name="log_out_failed_message">Didn\'t log out. Try later, it may be a problem in the network or in the provider. If the problem persists, then wipe Bitmask data from the Android settings</string>
<string name="login.riseup.warning">"Riseup users: You need to create a separate account to use the VPN service"</string>
<string name="succesful_authentication_message">Authentication succeeded.</string>
<string name="authentication_failed_message">Authentication failed.</string>
@@ -67,10 +63,18 @@
<string name="eip_cancel_connect_title">Cancel connection?</string>
<string name="eip_cancel_connect_text">There is a connection attempt in progress. Do you wish to cancel it?</string>
<string name="eip.warning.browser_inconsistency">In order to avoid leaking your personal information, please close your browser and start a private window after disconnecting the Encrypted VPN Internet Access. Thanks.</string>
- <string name="yes">Yes</string>
- <string name="no">No</string>
<string name="eip_state_not_connected">"Not running! Connection not secure!"</string>
<string name="eip_state_connected">Connection Secure.</string>
<string name="provider_problem">It seems there is a problem with the provider.</string>
<string name="try_another_provider">Please try another provider, or contact yours.</string>
+ <string name="default_username">Anonymous</string>
+ <string name="logged_in_user_status">is logged in.</string>
+ <string name="logged_out_user_status">logged out.</string>
+ <string name="didnt_log_out_user_status">didn\'t log out. Try later, it may be a problem in the network or in the provider. If the problem persists, then wipe Bitmask data from the Android settings</string>
+ <string name="not_logged_in_user_status">have not logged in.</string>
+ <string name="logging_in_user_status">is logging in.</string>
+ <string name="logging_out_user_status">is logging out.</string>
+ <string name="signingup_message">is being registered.</string>
+ <string name="vpn.button.turn.on">Turn on</string>
+ <string name="vpn.button.turn.off">Turn off</string>
</resources>
diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml
index 3aa47129..a73cad33 100644
--- a/app/src/main/res/values/untranslatable.xml
+++ b/app/src/main/res/values/untranslatable.xml
@@ -4030,4 +4030,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
</resources> \ No newline at end of file
diff --git a/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java b/app/src/production/java/se/leap/bitmaskclient/ConfigurationWizard.java
index 19ba1ba8..61c6b7cf 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ConfigurationWizard.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ConfigurationWizard.java
@@ -39,6 +39,7 @@ import se.leap.bitmaskclient.NewProviderDialog.NewProviderDialogInterface;
import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
import se.leap.bitmaskclient.ProviderDetailFragment.ProviderDetailFragmentInterface;
import se.leap.bitmaskclient.eip.Constants;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
/**
* Activity that builds and shows the list of known available providers.
@@ -98,8 +99,7 @@ public class ConfigurationWizard extends Activity
outState.putInt(PROGRESSBAR_NUMBER, mProgressBar.getProgress());
if (progressbar_description != null)
outState.putString(PROGRESSBAR_TEXT, progressbar_description.getText().toString());
- if (selected_provider != null)
- outState.putParcelable(Provider.KEY, selected_provider);
+ outState.putParcelable(Provider.KEY, selected_provider);
super.onSaveInstanceState(outState);
}
@@ -125,8 +125,7 @@ public class ConfigurationWizard extends Activity
selected_provider = savedInstanceState.getParcelable(Provider.KEY);
if (fragment_manager.findFragmentByTag(ProviderDetailFragment.TAG) == null && setting_up_provider) {
- if (selected_provider != null)
- onItemSelectedUi(selected_provider);
+ onItemSelectedUi();
if (progress > 0)
mProgressBar.setProgress(progress);
}
@@ -166,8 +165,7 @@ public class ConfigurationWizard extends Activity
}
private void setUpProviderAPIResultReceiver() {
- providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
- providerAPI_result_receiver.setReceiver(this);
+ providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), this);
providerAPI_broadcast_receiver_update = new ProviderAPIBroadcastReceiver_Update();
IntentFilter update_intent_filter = new IntentFilter(ProviderAPI.UPDATE_PROGRESSBAR);
@@ -195,8 +193,6 @@ public class ConfigurationWizard extends Activity
mProgressBar.incrementProgressBy(1);
hideProgressBar();
- setResult(RESULT_OK);
-
showProviderDetails();
}
} else if (resultCode == ProviderAPI.PROVIDER_NOK) {
@@ -213,8 +209,6 @@ public class ConfigurationWizard extends Activity
hideProgressBar();
showProviderDetails();
-
- setResult(RESULT_OK);
} else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
hideProgressBar();
@@ -229,17 +223,17 @@ public class ConfigurationWizard extends Activity
void onItemSelected(int position) {
//TODO Code 2 pane view
selected_provider = adapter.getItem(position);
- onItemSelectedUi(selected_provider);
- onItemSelectedLogic(selected_provider);
+ onItemSelectedUi();
+ onItemSelectedLogic();
}
- private void onItemSelectedLogic(Provider selected_provider) {
- setUpProvider(selected_provider.mainUrl());
+ private void onItemSelectedLogic() {
+ setUpProvider();
}
- private void onItemSelectedUi(Provider provider) {
+ private void onItemSelectedUi() {
startProgressBar();
- adapter.hideAllBut(adapter.indexOf(provider));
+ adapter.hideAllBut(adapter.indexOf(selected_provider));
}
@Override
@@ -379,8 +373,8 @@ public class ConfigurationWizard extends Activity
private void autoSelectProvider(Provider provider) {
selected_provider = provider;
- onItemSelectedUi(selected_provider);
- onItemSelectedLogic(selected_provider);
+ onItemSelectedUi();
+ onItemSelectedLogic();
}
/**
@@ -389,10 +383,11 @@ public class ConfigurationWizard extends Activity
* @param provider_name
* @param provider_main_url
*/
- public void setUpProvider(URL provider_main_url) {
+ public void setUpProvider() {
Intent provider_API_command = new Intent(this, ProviderAPI.class);
Bundle parameters = new Bundle();
- parameters.putString(Provider.MAIN_URL, provider_main_url.toString());
+ parameters.putString(Provider.MAIN_URL, selected_provider.mainUrl().toString());
+ parameters.putString(Provider.CA_CERT_FINGERPRINT, selected_provider.certificatePin());
provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER);
provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters);
diff --git a/app/src/release/java/se/leap/bitmaskclient/NewProviderDialog.java b/app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java
index 1823d3e3..1823d3e3 100644
--- a/app/src/release/java/se/leap/bitmaskclient/NewProviderDialog.java
+++ b/app/src/production/java/se/leap/bitmaskclient/NewProviderDialog.java
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/production/java/se/leap/bitmaskclient/ProviderAPI.java
index 7cf80a4f..a3f7db6a 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -18,6 +18,7 @@ package se.leap.bitmaskclient;
import android.app.*;
import android.content.*;
+import android.content.res.*;
import android.os.*;
import android.util.*;
@@ -33,9 +34,12 @@ import javax.net.ssl.*;
import org.apache.http.client.*;
import org.json.*;
+import org.thoughtcrime.ssl.pinning.util.*;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.userstatus.SessionDialog;
+import se.leap.bitmaskclient.userstatus.User;
+import se.leap.bitmaskclient.userstatus.UserStatus;
/**
* Implements HTTP api methods used to manage communications with the provider server.
@@ -86,6 +90,8 @@ public class ProviderAPI extends IntentService {
private static boolean go_ahead = true;
private static SharedPreferences preferences;
private static String provider_api_url;
+ private static String provider_ca_cert_fingerprint;
+ private Resources resources;
public static void stop() {
go_ahead = false;
@@ -137,7 +143,7 @@ public class ProviderAPI extends IntentService {
}
}
} else if (action.equalsIgnoreCase(SIGN_UP)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.SIGNING_UP);
+ UserStatus.updateStatus(UserStatus.SessionStatus.SIGNING_UP, resources);
Bundle result = tryToRegister(parameters);
if (result.getBoolean(RESULT_KEY)) {
receiver.send(SUCCESSFUL_SIGNUP, result);
@@ -145,23 +151,23 @@ public class ProviderAPI extends IntentService {
receiver.send(FAILED_SIGNUP, result);
}
} else if (action.equalsIgnoreCase(LOG_IN)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_IN, resources);
Bundle result = tryToAuthenticate(parameters);
if (result.getBoolean(RESULT_KEY)) {
receiver.send(SUCCESSFUL_LOGIN, result);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_IN, resources);
} else {
receiver.send(FAILED_LOGIN, result);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.NOT_LOGGED_IN);
+ UserStatus.updateStatus(UserStatus.SessionStatus.NOT_LOGGED_IN, resources);
}
} else if (action.equalsIgnoreCase(LOG_OUT)) {
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGING_OUT);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_OUT, resources);
if (logOut()) {
receiver.send(SUCCESSFUL_LOGOUT, Bundle.EMPTY);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.LOGGED_OUT);
+ UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_OUT, resources);
} else {
receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
- UserSessionStatus.updateStatus(UserSessionStatus.SessionStatus.DIDNT_LOG_OUT);
+ UserStatus.updateStatus(UserStatus.SessionStatus.DIDNT_LOG_OUT, resources);
}
} else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
if (updateVpnCertificate()) {
@@ -414,6 +420,8 @@ public class ProviderAPI extends IntentService {
InputStream is = null;
urlConnection = (HttpsURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod(request_method);
+ String locale = Locale.getDefault().getLanguage() + Locale.getDefault().getCountry();
+ urlConnection.setRequestProperty("Accept-Language", locale);
urlConnection.setChunkedStreamingMode(0);
urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory());
@@ -500,13 +508,19 @@ public class ProviderAPI extends IntentService {
Bundle current_download = new Bundle();
if (task != null && task.containsKey(Provider.MAIN_URL)) {
- last_provider_main_url = task.getString(Provider.MAIN_URL);
+ last_provider_main_url = task.containsKey(Provider.MAIN_URL) ?
+ task.getString(Provider.MAIN_URL) :
+ "";
+ provider_ca_cert_fingerprint = task.containsKey(Provider.CA_CERT_FINGERPRINT) ?
+ task.getString(Provider.CA_CERT_FINGERPRINT) :
+ "";
+
CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false;
go_ahead = true;
}
if (!PROVIDER_JSON_DOWNLOADED)
- current_download = getAndSetProviderJson(last_provider_main_url);
+ current_download = getAndSetProviderJson(last_provider_main_url, provider_ca_cert_fingerprint);
if (PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
broadcastProgress(progress++);
PROVIDER_JSON_DOWNLOADED = true;
@@ -598,11 +612,16 @@ public class ProviderAPI extends IntentService {
return hexData.toString();
}
- private Bundle getAndSetProviderJson(String provider_main_url) {
+ private Bundle getAndSetProviderJson(String provider_main_url, String provider_ca_cert_fingerprint) {
Bundle result = new Bundle();
if (go_ahead) {
- String provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json");
+ String provider_dot_json_string;
+
+ if(provider_ca_cert_fingerprint.isEmpty())
+ provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json");
+ else
+ provider_dot_json_string = downloadWithCommercialCA(provider_main_url + "/provider.json", provider_ca_cert_fingerprint);
try {
JSONObject provider_json = new JSONObject(provider_dot_json_string);
@@ -668,6 +687,28 @@ public class ProviderAPI extends IntentService {
return error_message;
}
+ private String downloadWithCommercialCA(String url_string, String ca_cert_fingerprint) {
+ String result = "";
+
+ int seconds_of_timeout = 2;
+ String[] pins = new String[] {ca_cert_fingerprint};
+ try {
+ URL url = new URL(url_string);
+ HttpsURLConnection connection = PinningHelper.getPinnedHttpsURLConnection(Dashboard.getContext(), pins, url);
+ connection.setConnectTimeout(seconds_of_timeout * 1000);
+ if (!LeapSRPSession.getToken().isEmpty())
+ connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken());
+ result = new Scanner(connection.getInputStream()).useDelimiter("\\A").next();
+ } catch (IOException e) {
+ if(e instanceof SSLHandshakeException)
+ result = formatErrorMessage(R.string.error_security_pinnedcertificate);
+ else
+ result = formatErrorMessage(R.string.error_io_exception_user_message);
+ }
+
+ return result;
+ }
+
/**
* Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider.
*
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderDetailFragment.java b/app/src/production/java/se/leap/bitmaskclient/ProviderDetailFragment.java
index 24d048a6..08fc5f3d 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderDetailFragment.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderDetailFragment.java
@@ -1,111 +1,111 @@
-package se.leap.bitmaskclient;
-
-import org.json.*;
-
-import se.leap.bitmaskclient.eip.*;
-import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-
-import android.app.*;
-import android.content.*;
-import android.os.*;
-import android.view.*;
-import android.widget.*;
-
-public class ProviderDetailFragment extends DialogFragment {
-
- final public static String TAG = "providerDetailFragment";
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- try {
-
- LayoutInflater inflater = getActivity().getLayoutInflater();
- View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null);
-
- JSONObject provider_json = new JSONObject(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, getActivity().MODE_PRIVATE).getString(Provider.KEY, ""));
-
- final TextView domain = (TextView) provider_detail_view.findViewById(R.id.provider_detail_domain);
- domain.setText(provider_json.getString(Provider.DOMAIN));
- final TextView name = (TextView) provider_detail_view.findViewById(R.id.provider_detail_name);
- name.setText(provider_json.getJSONObject(Provider.NAME).getString("en"));
- final TextView description = (TextView) provider_detail_view.findViewById(R.id.provider_detail_description);
- description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en"));
-
- builder.setView(provider_detail_view);
- builder.setTitle(R.string.provider_details_fragment_title);
-
- if (anon_allowed(provider_json)) {
- builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.use_anonymously();
- }
- });
- }
-
- if (registration_allowed(provider_json)) {
- builder.setNegativeButton(R.string.signup_or_login_button, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- interface_with_configuration_wizard.login();
- }
- });
- }
-
- return builder.create();
- } catch (JSONException e) {
- return null;
- }
- }
-
- private boolean anon_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(Constants.ALLOWED_ANON) && service_description.getBoolean(Constants.ALLOWED_ANON);
- } catch (JSONException e) {
- return false;
- }
- }
-
- private boolean registration_allowed(JSONObject provider_json) {
- try {
- JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
- return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION);
- } catch (JSONException e) {
- return false;
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- SharedPreferences.Editor editor = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit();
- editor.remove(Provider.KEY).remove(Constants.ALLOWED_ANON).remove(Constants.KEY).commit();
- interface_with_configuration_wizard.showAllProviders();
- }
-
- public static DialogFragment newInstance() {
- ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment();
- return provider_detail_fragment;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString()
- + " must implement LogInDialogListener");
- }
- }
-
- public interface ProviderDetailFragmentInterface {
- public void login();
-
- public void use_anonymously();
-
- public void showAllProviders();
- }
-
- ProviderDetailFragmentInterface interface_with_configuration_wizard;
-}
+package se.leap.bitmaskclient;
+
+import org.json.*;
+
+import se.leap.bitmaskclient.eip.*;
+import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
+
+import android.app.*;
+import android.content.*;
+import android.os.*;
+import android.view.*;
+import android.widget.*;
+
+public class ProviderDetailFragment extends DialogFragment {
+
+ final public static String TAG = "providerDetailFragment";
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ try {
+
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null);
+
+ JSONObject provider_json = new JSONObject(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, getActivity().MODE_PRIVATE).getString(Provider.KEY, ""));
+
+ final TextView domain = (TextView) provider_detail_view.findViewById(R.id.provider_detail_domain);
+ domain.setText(provider_json.getString(Provider.DOMAIN));
+ final TextView name = (TextView) provider_detail_view.findViewById(R.id.provider_detail_name);
+ name.setText(provider_json.getJSONObject(Provider.NAME).getString("en"));
+ final TextView description = (TextView) provider_detail_view.findViewById(R.id.provider_detail_description);
+ description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en"));
+
+ builder.setView(provider_detail_view);
+ builder.setTitle(R.string.provider_details_fragment_title);
+
+ if (anon_allowed(provider_json)) {
+ builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ interface_with_configuration_wizard.use_anonymously();
+ }
+ });
+ }
+
+ if (registration_allowed(provider_json)) {
+ builder.setNegativeButton(R.string.signup_or_login_button, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ interface_with_configuration_wizard.login();
+ }
+ });
+ }
+
+ return builder.create();
+ } catch (JSONException e) {
+ return null;
+ }
+ }
+
+ private boolean anon_allowed(JSONObject provider_json) {
+ try {
+ JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
+ return service_description.has(Constants.ALLOWED_ANON) && service_description.getBoolean(Constants.ALLOWED_ANON);
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ private boolean registration_allowed(JSONObject provider_json) {
+ try {
+ JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
+ return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION);
+ } catch (JSONException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ SharedPreferences.Editor editor = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit();
+ editor.remove(Provider.KEY).remove(Constants.ALLOWED_ANON).remove(Constants.KEY).commit();
+ interface_with_configuration_wizard.showAllProviders();
+ }
+
+ public static DialogFragment newInstance() {
+ ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment();
+ return provider_detail_fragment;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(activity.toString()
+ + " must implement LogInDialogListener");
+ }
+ }
+
+ public interface ProviderDetailFragmentInterface {
+ public void login();
+
+ public void use_anonymously();
+
+ public void showAllProviders();
+ }
+
+ ProviderDetailFragmentInterface interface_with_configuration_wizard;
+}
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderListContent.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java
index 235ae5ab..6466e769 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderListContent.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java
@@ -1,81 +1,81 @@
-/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package se.leap.bitmaskclient;
-
-import java.util.*;
-import java.net.*;
-
-/**
- * Models the provider list shown in the ConfigurationWizard.
- *
- * @author parmegv
- */
-public class ProviderListContent {
-
- public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>();
-
- public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>();
-
- /**
- * Adds a new provider item to the end of the items map, and to the items list.
- *
- * @param item
- */
- public static void addItem(ProviderItem item) {
- ITEMS.add(item);
- ITEM_MAP.put(String.valueOf(ITEMS.size()), item);
- }
-
- public static void removeItem(ProviderItem item) {
- ITEMS.remove(item);
- ITEM_MAP.remove(item);
- }
-
- /**
- * A provider item.
- */
- public static class ProviderItem {
- final public static String CUSTOM = "custom";
- private String provider_main_url;
- private String name;
-
- /**
- * @param name of the provider
- * @param provider_main_url used to download provider.json file of the provider
- */
- public ProviderItem(String name, String provider_main_url) {
- this.name = name;
- this.provider_main_url = provider_main_url;
- }
-
- public String name() {
- return name;
- }
-
- public String providerMainUrl() {
- return provider_main_url;
- }
-
- public String domain() {
- try {
- return new URL(provider_main_url).getHost();
- } catch (MalformedURLException e) {
- return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", "");
- }
- }
- }
-}
+/**
+ * Copyright (c) 2013 LEAP Encryption Access Project and contributers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package se.leap.bitmaskclient;
+
+import java.util.*;
+import java.net.*;
+
+/**
+ * Models the provider list shown in the ConfigurationWizard.
+ *
+ * @author parmegv
+ */
+public class ProviderListContent {
+
+ public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>();
+
+ public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>();
+
+ /**
+ * Adds a new provider item to the end of the items map, and to the items list.
+ *
+ * @param item
+ */
+ public static void addItem(ProviderItem item) {
+ ITEMS.add(item);
+ ITEM_MAP.put(String.valueOf(ITEMS.size()), item);
+ }
+
+ public static void removeItem(ProviderItem item) {
+ ITEMS.remove(item);
+ ITEM_MAP.remove(item);
+ }
+
+ /**
+ * A provider item.
+ */
+ public static class ProviderItem {
+ final public static String CUSTOM = "custom";
+ private String provider_main_url;
+ private String name;
+
+ /**
+ * @param name of the provider
+ * @param provider_main_url used to download provider.json file of the provider
+ */
+ public ProviderItem(String name, String provider_main_url) {
+ this.name = name;
+ this.provider_main_url = provider_main_url;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String providerMainUrl() {
+ return provider_main_url;
+ }
+
+ public String domain() {
+ try {
+ return new URL(provider_main_url).getHost();
+ } catch (MalformedURLException e) {
+ return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", "");
+ }
+ }
+ }
+}
diff --git a/app/src/release/res/layout-xlarge/new_provider_dialog.xml b/app/src/production/res/layout-xlarge/new_provider_dialog.xml
index 12616625..12616625 100644
--- a/app/src/release/res/layout-xlarge/new_provider_dialog.xml
+++ b/app/src/production/res/layout-xlarge/new_provider_dialog.xml
diff --git a/app/src/release/res/layout/new_provider_dialog.xml b/app/src/production/res/layout/new_provider_dialog.xml
index 36eb0d6a..36eb0d6a 100644
--- a/app/src/release/res/layout/new_provider_dialog.xml
+++ b/app/src/production/res/layout/new_provider_dialog.xml