Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
da213e0
Add instrumented tests for Preferences
Sep 3, 2025
25fa80d
Add methods to get and set enforcement of relay connection
Sep 3, 2025
4df11fd
Fix example instrumented test
Sep 3, 2025
fc20caa
Add instrumented test to get EnvList
Sep 3, 2025
d7175d7
Add packager for environment variables
Sep 3, 2025
3d0a1c9
Send list of environment variables to Android go client
Sep 3, 2025
52cdf0a
Add strings for 'enforce relay connection' in advanced settings
doromaraujo Sep 4, 2025
d2296c7
Add reusable component switch layout
doromaraujo Sep 4, 2025
23e2c84
Add 'Enforce relay connection' to advanced configuration
doromaraujo Sep 4, 2025
f914faa
Refactor 'force relay connection' layout id
doromaraujo Sep 4, 2025
b6f4a2d
Refactor 'force relay connection' feature references
doromaraujo Sep 4, 2025
86d4a5a
Add simple dialog to display alert messages
doromaraujo Sep 5, 2025
6337115
Display alert message when force relay is toggled
doromaraujo Sep 5, 2025
318e561
Add ID to advanced fragment's ScrollView
doromaraujo Sep 5, 2025
9e89f6a
Add optional transparent background theme for AlertDialogs
doromaraujo Sep 5, 2025
5cda763
Add round border shape whose color varies with the theme
doromaraujo Sep 5, 2025
8e347f3
Add rounded corners to simple alert message dialog layout
doromaraujo Sep 5, 2025
1b00c07
Add AlertDialogTheme to dialog shown on force relay toggle
doromaraujo Sep 5, 2025
95c9a80
Update netbird's submodule reference to 64c1c6
doromaraujo Sep 5, 2025
c373ef9
Update "reconnection needed" text
doromaraujo Sep 8, 2025
3cba603
Update netbird's submodule reference to a53243
doromaraujo Sep 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {

Expand Down Expand Up @@ -122,6 +153,8 @@ public View onCreateView(@NonNull LayoutInflater inflater,
}
});

configureForceRelayConnectionSwitch(binding.layoutForceRelayConnection, preferences);

// Initialize engine config switches (your settings)
initializeEngineConfigSwitches();

Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/drawable/bg_rounded_nb_bg.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="28dp" />
<solid android:color="@color/nb_bg" />
</shape>
40 changes: 40 additions & 0 deletions app/src/main/res/layout/component_switch.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">

<TextView
android:id="@+id/switch_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Switch Title"
android:textColor="@color/nb_txt_light" />

<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_control"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

<TextView
android:id="@+id/switch_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Switch Description"
android:textColor="@color/nb_txt_light"
android:textSize="12sp"
android:layout_marginTop="2dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="48dp" />

</LinearLayout>
44 changes: 44 additions & 0 deletions app/src/main/res/layout/dialog_simple_alert_message.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_rounded_nb_bg"
android:maxWidth="560dp"
android:minWidth="280dp"
android:padding="24dp">

<ImageView
android:id="@+id/icon_dialog"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/exclamation_mark"
android:src="@drawable/exclamation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/nb_orange" />

<TextView
android:id="@+id/txt_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/icon_dialog"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ultricies, lorem sit amet ultrices tincidunt, neque neque molestie lacus, dictum consequat sapien neque at quam. Proin vel justo nulla." />

<com.google.android.material.button.MaterialButton
android:id="@+id/btn_ok_dialog"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="@android:string/ok"
android:textColor="@color/nb_orange"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/txt_dialog"
tools:text="@android:string/ok" />

</androidx.constraintlayout.widget.ConstraintLayout>
15 changes: 13 additions & 2 deletions app/src/main/res/layout/fragment_advanced.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">

<androidx.constraintlayout.widget.ConstraintLayout
Expand Down Expand Up @@ -43,7 +44,7 @@
android:textSize="14sp"
android:inputType="textUri"
android:background="@drawable/edit_text_white"
android:padding="12dp"
android:padding="16dp"
android:textColor="@color/nb_txt"
android:textColorHint="@color/nb_txt_light"
app:layout_constraintTop_toBottomOf="@id/text_server_label"
Expand Down Expand Up @@ -438,13 +439,23 @@

</LinearLayout>

<include
android:id="@+id/layout_force_relay_connection"
layout="@layout/component_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/layout_disable_firewall" />

<LinearLayout
android:id="@+id/layout_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/layout_disable_firewall"
app:layout_constraintTop_toBottomOf="@id/layout_force_relay_connection"
app:layout_constraintEnd_toEndOf="parent">

<TextView
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,8 @@
<string name="advanced_theme_dark">Dark</string>
<string name="advanced_theme_light">Light</string>
<string name="advanced_theme_desc">Choose the app appearance mode.</string>
<string name="advanced_force_relay_conn">Force relay connection</string>
<string name="advanced_force_relay_conn_desc">Forces usage of relay when connecting to peers</string>
<string name="exclamation_mark">exclamation mark</string>
<string name="reconnectionNeededWarningMessage">To apply the setting, you will need to reconnect.</string>
</resources>
4 changes: 4 additions & 0 deletions app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@
<item name="trackTint">@color/switch_track_color</item>
</style>
<attr name="nbTabBackground" format="color|reference" />

<style name="AlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
</resources>
2 changes: 1 addition & 1 deletion netbird
Submodule netbird updated 161 files
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
7 changes: 5 additions & 2 deletions tool/src/main/java/io/netbird/client/tool/EngineRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions tool/src/main/java/io/netbird/client/tool/EnvVarPackager.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading
Loading