diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 1df0b4897..fd3030e50 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -102,6 +102,8 @@
Connect via Bluetooth
Whenever contacts are nearby
Only when adding contacts
+ TOR
+ Use Tor over WiFi Only
NOTIFICATIONS
Show alerts for private messages
Show alerts for forum posts
diff --git a/briar-android/src/org/briarproject/android/SettingsActivity.java b/briar-android/src/org/briarproject/android/SettingsActivity.java
index 5bc03653c..fdbf99120 100644
--- a/briar-android/src/org/briarproject/android/SettingsActivity.java
+++ b/briar-android/src/org/briarproject/android/SettingsActivity.java
@@ -67,6 +67,7 @@ OnClickListener {
private TextView enableBluetooth = null, enableBluetoothHint = null;
private CheckBox notifyPrivateMessages = null, notifyGroupPosts = null;
private CheckBox notifyVibration = null;
+ private CheckBox torOverWifi = null;
private TextView notifySound = null, notifySoundHint = null;
private ListLoadingProgressBar progress = null;
private ImageButton testingButton = null;
@@ -117,6 +118,23 @@ OnClickListener {
enableBluetoothHint.setOnClickListener(this);
settings.addView(enableBluetoothHint);
+ TextView torTitle = new TextView(this);
+ torTitle.setPadding(pad, 0, pad, 0);
+ torTitle.setTypeface(DEFAULT_BOLD);
+ torTitle.setTextColor(titleText);
+ torTitle.setText(R.string.tor_wifi_setting_title);
+ settings.addView(torTitle);
+
+ underline = new HorizontalBorder(this);
+ underline.setBackgroundColor(titleUnderline);
+ settings.addView(underline);
+
+ torOverWifi = new CheckBox(this);
+ torOverWifi.setTextSize(18);
+ torOverWifi.setText(R.string.tor_wifi_setting);
+ torOverWifi.setOnClickListener(this);
+ settings.addView(torOverWifi);
+
TextView notificationsTitle = new TextView(this);
notificationsTitle.setPadding(pad, 0, pad, 0);
notificationsTitle.setTypeface(DEFAULT_BOLD);
@@ -280,6 +298,8 @@ OnClickListener {
}
storeBluetoothSetting();
displaySettings();
+ } else if (view == torOverWifi) {
+ storeTorSettings();
} else if (view == notifyPrivateMessages) {
Settings s = new Settings();
s.putBoolean("notifyPrivateMessages",
@@ -312,6 +332,24 @@ OnClickListener {
}
}
+ private void storeTorSettings() {
+ runOnDbThread(new Runnable() {
+ public void run() {
+ Settings s = new Settings();
+ s.putBoolean("torOverWifi", torOverWifi.isChecked());
+ TransportConfig c = new TransportConfig();
+ c.putBoolean("torOverWifi", torOverWifi.isChecked());
+ storeSettings(s);
+ try {
+ db.mergeConfig(new TransportId("tor"), c);
+ } catch (DbException e) {
+ if (LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ }
+ }
+ });
+ }
+
private void storeBluetoothSetting() {
runOnDbThread(new Runnable() {
public void run() {
diff --git a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
index 12624c0dd..201639623 100644
--- a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
+++ b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java
@@ -13,6 +13,7 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.system.LocationUtils;
+import org.briarproject.api.event.EventBus;
import org.briarproject.plugins.droidtooth.DroidtoothPluginFactory;
import org.briarproject.plugins.tcp.AndroidLanTcpPluginFactory;
import org.briarproject.plugins.tor.TorPluginFactory;
@@ -36,12 +37,13 @@ public class AndroidPluginsModule extends PluginsModule {
@Provides
DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor,
AndroidExecutor androidExecutor, Application app,
- CryptoComponent crypto, LocationUtils locationUtils) {
+ CryptoComponent crypto, LocationUtils locationUtils,
+ EventBus eventBus) {
Context appContext = app.getApplicationContext();
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
androidExecutor, appContext, crypto.getSecureRandom());
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
- locationUtils);
+ locationUtils, eventBus);
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
appContext);
final Collection factories =
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index 7cb0be299..4d16f6eb6 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -50,11 +50,18 @@ import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.MODE_PRIVATE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+
+import org.briarproject.api.event.EventListener;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.SettingsUpdatedEvent;
+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
-class TorPlugin implements DuplexPlugin, EventHandler {
+class TorPlugin implements DuplexPlugin, EventHandler,
+ EventListener {
static final TransportId ID = new TransportId("tor");
@@ -82,6 +89,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
private volatile boolean running = false, networkEnabled = false;
private volatile boolean bootstrapped = false;
+ private volatile boolean connectedToWifi = false;
+ private volatile boolean online = false;
+
private volatile ServerSocket socket = null;
private volatile Socket controlSocket = null;
private volatile TorControlConnection controlConnection = null;
@@ -585,27 +595,94 @@ class TorPlugin implements DuplexPlugin, EventHandler {
@Override
public void onReceive(Context ctx, Intent i) {
+
if (!running) return;
- boolean online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
+
+ Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
+ ConnectivityManager cm = (ConnectivityManager) o;
+ NetworkInfo net = cm.getActiveNetworkInfo();
+
+ /* Some devices fail to set EXTRA_NO_CONNECTIVITY, double check */
+ online = !i.getBooleanExtra(EXTRA_NO_CONNECTIVITY, false);
if (online) {
- // Some devices fail to set EXTRA_NO_CONNECTIVITY, double check
- Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
- ConnectivityManager cm = (ConnectivityManager) o;
- NetworkInfo net = cm.getActiveNetworkInfo();
if (net == null || !net.isConnected()) online = false;
}
- String country = locationUtils.getCurrentCountry();
- if (LOG.isLoggable(INFO)) {
- LOG.info("Online: " + online);
- if ("".equals(country)) LOG.info("Country code unknown");
- else LOG.info("Country code: " + country);
- }
- boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(country);
- try {
- enableNetwork(online && !blocked);
- } catch (IOException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- }
+
+ connectedToWifi = (net != null && net.getType() == TYPE_WIFI
+ && net.isConnected());
+
+ updateConnectionStatus();
}
}
+
+ public void eventOccurred(Event e) {
+ if (e instanceof SettingsUpdatedEvent) {
+ if (!running) return;
+
+ updateConnectionStatus();
+ }
+ }
+
+ private void updateConnectionStatus() {
+
+ ioExecutor.execute(new Runnable() {
+
+ public void run() {
+
+ boolean wifiOnly = false;
+ boolean blocked = false;
+
+ String country = locationUtils.getCurrentCountry();
+ if (LOG.isLoggable(INFO)) {
+ LOG.info("Online: " + online);
+ if ("".equals(country)) LOG.info("Country code unknown");
+ else LOG.info("Country code: " + country);
+ }
+ blocked = TorNetworkMetadata.isTorProbablyBlocked(country);
+ TransportConfig c = callback.getConfig();
+ wifiOnly = c.getBoolean("torOverWifi", false);
+
+ try {
+ /*
+ 1) Disable network if offline
+ */
+ if (!online) {
+ LOG.log(WARNING, "Disabling network, network is offline");
+ enableNetwork(false);
+ return;
+ }
+
+ /*
+ 2) Disable network if blocked
+ */
+ if (blocked) {
+ LOG.log(WARNING, "Disabling network, country is blocked");
+ enableNetwork(false);
+ return;
+ }
+
+ /*
+ 3) Disable network if wifiOnly and not connected to
+ wifi
+ */
+ if (wifiOnly & !connectedToWifi){
+ LOG.log(WARNING, "Disabling network due to wifi only setting");
+ enableNetwork(false);
+ return;
+ }
+
+ /*
+ 4) Otherwise enable network
+ */
+ enableNetwork(true);
+
+ } catch (IOException e) {
+ if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ }
+
+ }
+
+ });
+ }
+
}
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
index 9e38a5a37..d9472ad44 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java
@@ -3,6 +3,8 @@ package org.briarproject.plugins.tor;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
+import org.briarproject.api.event.EventBus;
+
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.TransportId;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
@@ -25,12 +27,14 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final Executor ioExecutor;
private final Context appContext;
private final LocationUtils locationUtils;
+ private final EventBus eventBus;
public TorPluginFactory(Executor ioExecutor, Context appContext,
- LocationUtils locationUtils) {
+ LocationUtils locationUtils, EventBus eventBus) {
this.ioExecutor = ioExecutor;
this.appContext = appContext;
this.locationUtils = locationUtils;
+ this.eventBus = eventBus;
}
public TransportId getId() {
@@ -38,6 +42,9 @@ public class TorPluginFactory implements DuplexPluginFactory {
}
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
+
+ TorPlugin thisPlugin = null;
+
// Check that we have a Tor binary for this architecture
String architecture = null;
for (String abi : AndroidUtils.getSupportedArchitectures()) {
@@ -55,7 +62,13 @@ public class TorPluginFactory implements DuplexPluginFactory {
}
// Use position-independent executable for SDK >= 16
if (Build.VERSION.SDK_INT >= 16) architecture += "-pie";
- return new TorPlugin(ioExecutor,appContext, locationUtils, callback,
- architecture, MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL);
+
+ thisPlugin = new TorPlugin(ioExecutor,appContext, locationUtils,
+ callback, architecture, MAX_LATENCY, MAX_IDLE_TIME,
+ POLLING_INTERVAL);
+ this.eventBus.addListener(thisPlugin);
+
+ return thisPlugin;
+
}
}