diff --git a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
index 5e4a96b..3e5bedb 100644
--- a/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
+++ b/app/src/main/java/io/netbird/client/ui/advanced/AdvancedFragment.java
@@ -9,12 +9,16 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioGroup;
+import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.Fragment;
+import io.netbird.client.R;
+import io.netbird.client.databinding.ComponentSwitchBinding;
import io.netbird.client.databinding.FragmentAdvancedBinding;
import io.netbird.client.tool.Logcat;
import io.netbird.client.tool.Preferences;
@@ -28,6 +32,33 @@ public class AdvancedFragment extends Fragment {
private FragmentAdvancedBinding binding;
private io.netbird.gomobile.android.Preferences goPreferences;
+ private void showReconnectionNeededWarningDialog() {
+ final View dialogView = getLayoutInflater().inflate(R.layout.dialog_simple_alert_message, null);
+ final AlertDialog alertDialog = new AlertDialog.Builder(requireContext(), R.style.AlertDialogTheme)
+ .setView(dialogView)
+ .create();
+
+ ((TextView)dialogView.findViewById(R.id.txt_dialog)).setText(R.string.reconnectionNeededWarningMessage);
+ dialogView.findViewById(R.id.btn_ok_dialog).setOnClickListener(v -> alertDialog.dismiss());
+ alertDialog.show();
+ }
+
+ private void configureForceRelayConnectionSwitch(@NonNull ComponentSwitchBinding binding, @NonNull Preferences preferences) {
+ binding.switchTitle.setText(R.string.advanced_force_relay_conn);
+ binding.switchDescription.setText(R.string.advanced_force_relay_conn_desc);
+
+ binding.switchControl.setChecked(preferences.isConnectionForceRelayed());
+ binding.switchControl.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ if (isChecked) {
+ preferences.enableForcedRelayConnection();
+ } else {
+ preferences.disableForcedRelayConnection();
+ }
+
+ showReconnectionNeededWarningDialog();
+ });
+ }
+
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
@@ -122,6 +153,8 @@ public View onCreateView(@NonNull LayoutInflater inflater,
}
});
+ configureForceRelayConnectionSwitch(binding.layoutForceRelayConnection, preferences);
+
// Initialize engine config switches (your settings)
initializeEngineConfigSwitches();
diff --git a/app/src/main/res/drawable/bg_rounded_nb_bg.xml b/app/src/main/res/drawable/bg_rounded_nb_bg.xml
new file mode 100644
index 0000000..25a4b5a
--- /dev/null
+++ b/app/src/main/res/drawable/bg_rounded_nb_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/component_switch.xml b/app/src/main/res/layout/component_switch.xml
new file mode 100644
index 0000000..7c24a32
--- /dev/null
+++ b/app/src/main/res/layout/component_switch.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_simple_alert_message.xml b/app/src/main/res/layout/dialog_simple_alert_message.xml
new file mode 100644
index 0000000..cd5f1b5
--- /dev/null
+++ b/app/src/main/res/layout/dialog_simple_alert_message.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_advanced.xml b/app/src/main/res/layout/fragment_advanced.xml
index 4fb5556..23d5013 100644
--- a/app/src/main/res/layout/fragment_advanced.xml
+++ b/app/src/main/res/layout/fragment_advanced.xml
@@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
+ android:id="@+id/scr_vw_advanced"
tools:context=".ui.advanced.AdvancedFragment">
+
+
Dark
Light
Choose the app appearance mode.
+ Force relay connection
+ Forces usage of relay when connecting to peers
+ exclamation mark
+ To apply the setting, you will need to reconnect.
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 3f725ed..5a24308 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -57,4 +57,8 @@
- @color/switch_track_color
+
+
\ No newline at end of file
diff --git a/netbird b/netbird
index f425870..a53243e 160000
--- a/netbird
+++ b/netbird
@@ -1 +1 @@
-Subproject commit f425870c8e76eb4997f225c8114fd9b32696599d
+Subproject commit a53243eed0c575d92545ac825ee8c376bf342926
diff --git a/tool/src/androidTest/java/io/netbird/client/tool/EnvVarPackagerInstrumentedTest.java b/tool/src/androidTest/java/io/netbird/client/tool/EnvVarPackagerInstrumentedTest.java
new file mode 100644
index 0000000..502eeed
--- /dev/null
+++ b/tool/src/androidTest/java/io/netbird/client/tool/EnvVarPackagerInstrumentedTest.java
@@ -0,0 +1,27 @@
+package io.netbird.client.tool;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.netbird.gomobile.android.Android;
+
+@RunWith(AndroidJUnit4.class)
+public class EnvVarPackagerInstrumentedTest {
+ @Test
+ public void shouldReturnEnvironmentVariables() {
+ var preferences = new Preferences(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ var environmentVariables = EnvVarPackager.getEnvironmentVariables(preferences);
+
+ Assert.assertNotNull(environmentVariables);
+ var forceRelay = environmentVariables.get(Android.getEnvKeyNBForceRelay());
+ var variableNotPresentInList = environmentVariables.get("UNKNOWN_VAR");
+ var emptyString = "";
+
+ Assert.assertNotEquals(emptyString, forceRelay);
+ Assert.assertEquals(emptyString, variableNotPresentInList);
+ }
+}
diff --git a/tool/src/androidTest/java/io/netbird/client/tool/ExampleInstrumentedTest.java b/tool/src/androidTest/java/io/netbird/client/tool/ExampleInstrumentedTest.java
index 1ba806e..af279fb 100644
--- a/tool/src/androidTest/java/io/netbird/client/tool/ExampleInstrumentedTest.java
+++ b/tool/src/androidTest/java/io/netbird/client/tool/ExampleInstrumentedTest.java
@@ -21,6 +21,6 @@ public class ExampleInstrumentedTest {
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- assertEquals("io.netbird.client.backend.test", appContext.getPackageName());
+ assertEquals("io.netbird.client.tool.test", appContext.getPackageName());
}
}
\ No newline at end of file
diff --git a/tool/src/androidTest/java/io/netbird/client/tool/PreferencesInstrumentedTest.java b/tool/src/androidTest/java/io/netbird/client/tool/PreferencesInstrumentedTest.java
new file mode 100644
index 0000000..cf7a7f2
--- /dev/null
+++ b/tool/src/androidTest/java/io/netbird/client/tool/PreferencesInstrumentedTest.java
@@ -0,0 +1,93 @@
+package io.netbird.client.tool;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.Context;
+
+@RunWith(AndroidJUnit4.class)
+public class PreferencesInstrumentedTest {
+ private static Preferences preferences;
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ @BeforeClass
+ public static void setUp() {
+ preferences = new Preferences(getContext());
+ }
+
+ @After
+ public void tearDown() {
+ getContext().getSharedPreferences("netbird", Context.MODE_PRIVATE).edit().clear().apply();
+ }
+
+ @Test
+ public void shouldCreatePreferencesWithoutThrownException() {
+ Preferences preferences = null;
+ Exception thrown = null;
+
+ try {
+ preferences = new Preferences(getContext());
+ } catch (Exception e) {
+ thrown = e;
+ }
+
+ Assert.assertNull(thrown);
+ Assert.assertNotNull(preferences);
+ }
+
+ @Test
+ public void shouldReturnFalseWhenConnectionForceRelayedIsNotSet() {
+ Assert.assertFalse(preferences.isConnectionForceRelayed());
+ }
+
+ @Test
+ public void shouldReturnTrueAfterEnablingForcedRelayConnection() {
+ preferences.enableForcedRelayConnection();
+
+ Assert.assertTrue(preferences.isConnectionForceRelayed());
+ }
+
+ @Test
+ public void shouldReturnFalseAfterDisablingForcedRelayConnection() {
+ preferences.enableForcedRelayConnection();
+ preferences.disableForcedRelayConnection();
+
+ Assert.assertFalse(preferences.isConnectionForceRelayed());
+ }
+
+ @Test
+ public void shouldReturnFalseWhenTraceLogIsNotSet() {
+ Assert.assertFalse(preferences.isTraceLogEnabled());
+ }
+
+ @Test
+ public void shouldReturnTrueAfterEnablingTraceLog() {
+ preferences.enableTraceLog();
+
+ Assert.assertTrue(preferences.isTraceLogEnabled());
+ }
+
+ @Test
+ public void shouldReturnFalseAfterDisablingTraceLog() {
+ preferences.enableTraceLog();
+ preferences.disableTraceLog();
+
+ Assert.assertFalse(preferences.isTraceLogEnabled());
+ }
+
+ @Test
+ public void shouldReturnCorrectDefaultServer() {
+ final var defaultServer = "https://api.netbird.io";
+
+ Assert.assertEquals(defaultServer, Preferences.defaultServer());
+ }
+}
diff --git a/tool/src/main/java/io/netbird/client/tool/EngineRunner.java b/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
index 331d329..55ec345 100644
--- a/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
+++ b/tool/src/main/java/io/netbird/client/tool/EngineRunner.java
@@ -60,12 +60,15 @@ private synchronized void runClient(URLOpener urlOpener) {
engineIsRunning = true;
Runnable r = () -> {
DNSWatch dnsWatch = new DNSWatch(context);
+ Preferences preferences = new Preferences(context);
+ var envList = EnvVarPackager.getEnvironmentVariables(preferences);
+
try {
notifyServiceStateListeners(true);
if(urlOpener == null) {
- goClient.runWithoutLogin(dnsWatch.dnsServers(), () -> dnsWatch.setDNSChangeListener(this::changed));
+ goClient.runWithoutLogin(dnsWatch.dnsServers(), () -> dnsWatch.setDNSChangeListener(this::changed), envList);
} else {
- goClient.run(urlOpener, dnsWatch.dnsServers(), () -> dnsWatch.setDNSChangeListener(this::changed));
+ goClient.run(urlOpener, dnsWatch.dnsServers(), () -> dnsWatch.setDNSChangeListener(this::changed), envList);
}
} catch (Exception e) {
Log.e(LOGTAG, "goClient error", e);
diff --git a/tool/src/main/java/io/netbird/client/tool/EnvVarPackager.java b/tool/src/main/java/io/netbird/client/tool/EnvVarPackager.java
new file mode 100644
index 0000000..f6413e9
--- /dev/null
+++ b/tool/src/main/java/io/netbird/client/tool/EnvVarPackager.java
@@ -0,0 +1,14 @@
+package io.netbird.client.tool;
+
+import io.netbird.gomobile.android.Android;
+import io.netbird.gomobile.android.EnvList;
+
+public class EnvVarPackager {
+ public static EnvList getEnvironmentVariables(Preferences preferences) {
+ var envList = new EnvList();
+
+ envList.put(Android.getEnvKeyNBForceRelay(), String.valueOf(preferences.isConnectionForceRelayed()));
+
+ return envList;
+ }
+}
diff --git a/tool/src/main/java/io/netbird/client/tool/Preferences.java b/tool/src/main/java/io/netbird/client/tool/Preferences.java
index e35b29d..1f9c7b7 100644
--- a/tool/src/main/java/io/netbird/client/tool/Preferences.java
+++ b/tool/src/main/java/io/netbird/client/tool/Preferences.java
@@ -6,6 +6,9 @@
public class Preferences {
private final String keyTraceLog = "tracelog";
+
+ private final String keyForceRelayConnection = "isConnectionForceRelayed";
+
private final SharedPreferences sharedPref;
public static String configFile(Context context){
@@ -27,6 +30,18 @@ public void disableTraceLog() {
sharedPref.edit().putBoolean(keyTraceLog, false).apply();
}
+ public boolean isConnectionForceRelayed() {
+ return sharedPref.getBoolean(keyForceRelayConnection, false);
+ }
+
+ public void enableForcedRelayConnection() {
+ sharedPref.edit().putBoolean(keyForceRelayConnection, true).apply();
+ }
+
+ public void disableForcedRelayConnection() {
+ sharedPref.edit().putBoolean(keyForceRelayConnection, false).apply();
+ }
+
public static String defaultServer() {
return "https://api.netbird.io";
}