diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
index a3ce75ff..fab8603d 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
@@ -13,6 +13,7 @@ import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -107,7 +108,11 @@ public class SettingsActivity extends SyncthingActivity {
private Preference mCategoryBackup;
+ /* Experimental options */
private CheckBoxPreference mUseRoot;
+ private CheckBoxPreference mUseTor;
+ private EditTextPreference mSocksProxyAddress;
+ private EditTextPreference mHttpProxyAddress;
private Preference mSyncthingVersion;
@@ -191,8 +196,10 @@ public class SettingsActivity extends SyncthingActivity {
Preference stResetDeltas = findPreference("st_reset_deltas");
mUseRoot = (CheckBoxPreference) findPreference(Constants.PREF_USE_ROOT);
- Preference useWakelock = findPreference(Constants.PREF_USE_WAKE_LOCK);
- Preference useTor = findPreference(Constants.PREF_USE_TOR);
+ Preference useWakelock = (CheckBoxPreference) findPreference(Constants.PREF_USE_WAKE_LOCK);
+ mUseTor = (CheckBoxPreference) findPreference(Constants.PREF_USE_TOR);
+ mSocksProxyAddress = (EditTextPreference) findPreference(Constants.PREF_SOCKS_PROXY_ADDRESS);
+ mHttpProxyAddress = (EditTextPreference) findPreference(Constants.PREF_HTTP_PROXY_ADDRESS);
mSyncthingVersion = findPreference("syncthing_version");
Preference appVersion = screen.findPreference("app_version");
@@ -211,9 +218,20 @@ public class SettingsActivity extends SyncthingActivity {
stResetDatabase.setOnPreferenceClickListener(this);
stResetDeltas.setOnPreferenceClickListener(this);
+ /* Experimental options */
mUseRoot.setOnPreferenceClickListener(this);
useWakelock.setOnPreferenceChangeListener((p, o) -> requireRestart());
- useTor.setOnPreferenceChangeListener((p, o) -> requireRestart());
+ mUseTor.setOnPreferenceChangeListener(this);
+
+ mSocksProxyAddress.setEnabled(!(Boolean) mUseTor.isChecked());
+ mSocksProxyAddress.setOnPreferenceChangeListener(this);
+ mHttpProxyAddress.setEnabled(!(Boolean) mUseTor.isChecked());
+ mHttpProxyAddress.setOnPreferenceChangeListener(this);
+
+ /* Initialize summaries */
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ handleSocksProxyPreferenceChange(screen.findPreference(Constants.PREF_SOCKS_PROXY_ADDRESS), mPreferences.getString(Constants.PREF_SOCKS_PROXY_ADDRESS, ""));
+ handleHttpProxyPreferenceChange(screen.findPreference(Constants.PREF_HTTP_PROXY_ADDRESS), mPreferences.getString(Constants.PREF_HTTP_PROXY_ADDRESS, ""));
try {
appVersion.setSummary(getActivity().getPackageManager()
@@ -392,6 +410,29 @@ public class SettingsActivity extends SyncthingActivity {
return false;
}
break;
+ case Constants.PREF_USE_TOR:
+ mSocksProxyAddress.setEnabled(!(Boolean) o);
+ mHttpProxyAddress.setEnabled(!(Boolean) o);
+ requireRestart();
+ break;
+ case Constants.PREF_SOCKS_PROXY_ADDRESS:
+ if (o.toString().trim().equals(mPreferences.getString(Constants.PREF_SOCKS_PROXY_ADDRESS, "")))
+ return false;
+ if (handleSocksProxyPreferenceChange(preference, o.toString().trim())) {
+ requireRestart();
+ } else {
+ return false;
+ }
+ break;
+ case Constants.PREF_HTTP_PROXY_ADDRESS:
+ if (o.toString().trim().equals(mPreferences.getString(Constants.PREF_HTTP_PROXY_ADDRESS, "")))
+ return false;
+ if (handleHttpProxyPreferenceChange(preference, o.toString().trim())) {
+ requireRestart();
+ } else {
+ return false;
+ }
+ break;
}
return true;
@@ -512,5 +553,43 @@ public class SettingsActivity extends SyncthingActivity {
}
}
}
+
+ /**
+ * Handles a new user input for the SOCKS proxy preference.
+ * Returns if the changed setting requires a restart.
+ */
+ private boolean handleSocksProxyPreferenceChange(Preference preference, String newValue) {
+ // Valid input is either a proxy address or an empty field to disable the proxy.
+ if (newValue.equals("")) {
+ preference.setSummary(getString(R.string.do_not_use_proxy) + " " + getString(R.string.generic_example) + ": " + getString(R.string.socks_proxy_address_example));
+ return true;
+ } else if (newValue.matches("^socks5://.*:\\d{1,5}$")) {
+ preference.setSummary(getString(R.string.use_proxy) + " " + newValue);
+ return true;
+ } else {
+ Toast.makeText(getActivity(), R.string.toast_invalid_socks_proxy_address, Toast.LENGTH_SHORT)
+ .show();
+ return false;
+ }
+ }
+
+ /**
+ * Handles a new user input for the HTTP(S) proxy preference.
+ * Returns if the changed setting requires a restart.
+ */
+ private boolean handleHttpProxyPreferenceChange(Preference preference, String newValue) {
+ // Valid input is either a proxy address or an empty field to disable the proxy.
+ if (newValue.equals("")) {
+ preference.setSummary(getString(R.string.do_not_use_proxy) + " " + getString(R.string.generic_example) + ": " + getString(R.string.http_proxy_address_example));
+ return true;
+ } else if (newValue.matches("^http://.*:\\d{1,5}$")) {
+ preference.setSummary(getString(R.string.use_proxy) + " " + newValue);
+ return true;
+ } else {
+ Toast.makeText(getActivity(), R.string.toast_invalid_http_proxy_address, Toast.LENGTH_SHORT)
+ .show();
+ return false;
+ }
+ }
}
}
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
index a2ead0f3..d70db660 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
@@ -17,6 +17,8 @@ public class Constants {
public static final String PREF_NOTIFICATION_TYPE = "notification_type";
public static final String PREF_USE_WAKE_LOCK = "wakelock_while_binary_running";
public static final String PREF_USE_TOR = "use_tor";
+ public static final String PREF_SOCKS_PROXY_ADDRESS = "socks_proxy_address";
+ public static final String PREF_HTTP_PROXY_ADDRESS = "http_proxy_address";
/**
* On Android 8.1, ACCESS_COARSE_LOCATION is required to access WiFi SSID.
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java
index 0becf4cc..54b810da 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java
@@ -376,6 +376,17 @@ public class SyncthingRunnable implements Runnable {
if (mPreferences.getBoolean(Constants.PREF_USE_TOR, false)) {
targetEnv.put("all_proxy", "socks5://localhost:9050");
targetEnv.put("ALL_PROXY_NO_FALLBACK", "1");
+ } else {
+ String socksProxyAddress = mPreferences.getString(Constants.PREF_SOCKS_PROXY_ADDRESS, "");
+ if (!socksProxyAddress.equals("")) {
+ targetEnv.put("all_proxy", socksProxyAddress);
+ }
+
+ String httpProxyAddress = mPreferences.getString(Constants.PREF_HTTP_PROXY_ADDRESS, "");
+ if (!httpProxyAddress.equals("")) {
+ targetEnv.put("http_proxy", httpProxyAddress);
+ targetEnv.put("https_proxy", httpProxyAddress);
+ }
}
if (mPreferences.getBoolean("use_legacy_hashing", false))
targetEnv.put("STHASHING", "standard");
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 12e3d25d..56506770 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,6 +18,9 @@ Please report any problems you encounter via Github.
Continue
+
+ Example
+
@@ -337,13 +340,29 @@ Please report any problems you encounter via Github.
Export Configuration
+
+ Connect through a proxy
+ Do not connect through a proxy
+
Keep the CPU awake while Syncthing is running
Use this setting if you experience unexpected disconnects while operating on battery. This will result in increased battery consumption.
Use Tor
- Force all traffic through Tor for increased privacy. Requires Orbot
+ Force all traffic through Tor for increased privacy. Requires Orbot. Disables proxy options.
+
+ SOCKS5 proxy
+ socks5://192.168.0.1:1080
+
+
+ Input violates proxy syntax \'socks5://[IP/HOSTNAME]:[PORT]\'
+
+ HTTP(S) proxy
+ http://192.168.0.1:8080
+
+
+ Input violates proxy syntax \'http://[IP/HOSTNAME]:[PORT]\'
Use legacy hashing
diff --git a/app/src/main/res/xml/app_settings.xml b/app/src/main/res/xml/app_settings.xml
index 4a870995..b736ee54 100644
--- a/app/src/main/res/xml/app_settings.xml
+++ b/app/src/main/res/xml/app_settings.xml
@@ -212,6 +212,18 @@
android:title="@string/use_tor_title"
android:summary="@string/use_tor_summary" />
+
+
+
+