diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index ab787cf37..b9119cccb 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -12,6 +12,9 @@
+
+
+
+
+
#FFFFFF
#2D3E50
#FFFFFF
+ #FFFFFF
#FFFFFF
#AAAAAA
#FFFFFF
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 338a01086..b452b23ea 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -16,7 +16,7 @@
This software has expired.\nPlease install a newer version.
Contacts
Forums
- Synchronize
+ Testing
Sign Out
Contacts
No contacts
diff --git a/briar-android/src/org/briarproject/android/DashboardActivity.java b/briar-android/src/org/briarproject/android/DashboardActivity.java
index f1f604f1e..956254c4f 100644
--- a/briar-android/src/org/briarproject/android/DashboardActivity.java
+++ b/briar-android/src/org/briarproject/android/DashboardActivity.java
@@ -2,7 +2,6 @@ package org.briarproject.android;
import static android.view.Gravity.CENTER;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.widget.Toast.LENGTH_SHORT;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
@@ -37,7 +36,6 @@ import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
-import android.widget.Toast;
public class DashboardActivity extends BriarActivity {
@@ -121,20 +119,19 @@ public class DashboardActivity extends BriarActivity {
});
buttons.add(forumsButton);
- Button syncButton = new Button(this);
- syncButton.setLayoutParams(matchMatch);
- syncButton.setBackgroundResource(0);
- syncButton.setCompoundDrawablesWithIntrinsicBounds(0,
- R.drawable.navigation_refresh, 0, 0);
- syncButton.setText(R.string.synchronize_button);
- syncButton.setOnClickListener(new OnClickListener() {
+ Button testingButton = new Button(this);
+ testingButton.setLayoutParams(matchMatch);
+ testingButton.setBackgroundResource(0);
+ testingButton.setCompoundDrawablesWithIntrinsicBounds(0,
+ R.drawable.action_help, 0, 0);
+ testingButton.setText(R.string.testing_button);
+ testingButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
- // FIXME: Hook this button up to an activity
- Toast.makeText(DashboardActivity.this,
- R.string.not_implemented_toast, LENGTH_SHORT).show();
+ startActivity(new Intent(DashboardActivity.this,
+ TestingActivity.class));
}
});
- buttons.add(syncButton);
+ buttons.add(testingButton);
Button signOutButton = new Button(this);
signOutButton.setLayoutParams(matchMatch);
@@ -157,7 +154,7 @@ public class DashboardActivity extends BriarActivity {
grid.setGravity(CENTER);
grid.setPadding(pad, pad, pad, pad);
Resources res = getResources();
- grid.setBackgroundColor(res.getColor(R.color.button_bar_background));
+ grid.setBackgroundColor(res.getColor(R.color.dashboard_background));
grid.setNumColumns(2);
grid.setAdapter(new BaseAdapter() {
diff --git a/briar-android/src/org/briarproject/android/TestingActivity.java b/briar-android/src/org/briarproject/android/TestingActivity.java
new file mode 100644
index 000000000..0ff9381ce
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/TestingActivity.java
@@ -0,0 +1,347 @@
+package org.briarproject.android;
+
+import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
+import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+import static android.content.Intent.ACTION_SEND;
+import static android.content.Intent.EXTRA_EMAIL;
+import static android.content.Intent.EXTRA_STREAM;
+import static android.content.Intent.EXTRA_SUBJECT;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.view.Gravity.CENTER;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.widget.LinearLayout.VERTICAL;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+import static org.briarproject.android.util.CommonLayoutParams.MATCH_MATCH;
+import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP;
+import static org.briarproject.android.util.CommonLayoutParams.MATCH_WRAP_1;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Scanner;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import org.briarproject.R;
+import org.briarproject.android.util.ElasticHorizontalSpace;
+import org.briarproject.android.util.HorizontalBorder;
+import org.briarproject.android.util.LayoutUtils;
+import org.briarproject.api.TransportId;
+import org.briarproject.api.android.AndroidExecutor;
+import org.briarproject.api.plugins.Plugin;
+import org.briarproject.api.plugins.PluginManager;
+import org.briarproject.util.StringUtils;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+public class TestingActivity extends BriarActivity implements OnClickListener {
+
+ private static final Logger LOG =
+ Logger.getLogger(TestingActivity.class.getName());
+
+ @Inject private AndroidExecutor androidExecutor;
+ @Inject private PluginManager pluginManager;
+ private ScrollView scroll = null;
+ private LinearLayout status = null;
+ private ImageButton refresh = null, share = null;
+ private File temp = null;
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setLayoutParams(MATCH_MATCH);
+ layout.setOrientation(VERTICAL);
+ layout.setGravity(CENTER_HORIZONTAL);
+
+ scroll = new ScrollView(this);
+ scroll.setLayoutParams(MATCH_WRAP_1);
+ status = new LinearLayout(this);
+ status.setOrientation(VERTICAL);
+ status.setGravity(CENTER_HORIZONTAL);
+ int pad = LayoutUtils.getPadding(this);
+ status.setPadding(pad, pad, pad, pad);
+ scroll.addView(status);
+ layout.addView(scroll);
+
+ layout.addView(new HorizontalBorder(this));
+
+ LinearLayout footer = new LinearLayout(this);
+ footer.setLayoutParams(MATCH_WRAP);
+ footer.setGravity(CENTER);
+ Resources res = getResources();
+ footer.setBackgroundColor(res.getColor(R.color.button_bar_background));
+ footer.addView(new ElasticHorizontalSpace(this));
+
+ refresh = new ImageButton(this);
+ refresh.setBackgroundResource(0);
+ refresh.setImageResource(R.drawable.navigation_refresh);
+ refresh.setOnClickListener(this);
+ footer.addView(refresh);
+ footer.addView(new ElasticHorizontalSpace(this));
+
+ share = new ImageButton(this);
+ share.setBackgroundResource(0);
+ share.setImageResource(R.drawable.social_share);
+ share.setOnClickListener(this);
+ footer.addView(share);
+ footer.addView(new ElasticHorizontalSpace(this));
+ layout.addView(footer);
+
+ setContentView(layout);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refresh();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if(temp != null) temp.delete();
+ }
+
+ public void onClick(View view) {
+ if(view == refresh) refresh();
+ else if(view == share) share();
+ }
+
+ private void refresh() {
+ status.removeAllViews();
+ new AsyncTask>() {
+
+ protected Map doInBackground(Void... args) {
+ return getStatusMap();
+ }
+
+ protected void onPostExecute(Map result) {
+ int pad = LayoutUtils.getPadding(TestingActivity.this);
+ for(Entry e : result.entrySet()) {
+ TextView title = new TextView(TestingActivity.this);
+ title.setTextSize(18);
+ title.setText(e.getKey());
+ status.addView(title);
+ TextView content = new TextView(TestingActivity.this);
+ content.setPadding(0, 0, 0, pad);
+ content.setText(e.getValue());
+ status.addView(content);
+ }
+ scroll.scrollTo(0, 0);
+ }
+ }.execute();
+ }
+
+ private Map getStatusMap() {
+ Map statusMap = new LinkedHashMap();
+ // Is mobile data available?
+ Object o = getSystemService(CONNECTIVITY_SERVICE);
+ ConnectivityManager cm = (ConnectivityManager) o;
+ NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE);
+ boolean mobileAvailable = mobile != null && mobile.isAvailable();
+ // Is mobile data enabled?
+ boolean mobileEnabled = false;
+ try {
+ Class> clazz = Class.forName(cm.getClass().getName());
+ Method method = clazz.getDeclaredMethod("getMobileDataEnabled");
+ method.setAccessible(true);
+ mobileEnabled = (Boolean) method.invoke(cm);
+ } catch(ClassNotFoundException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ } catch(NoSuchMethodException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ } catch(IllegalAccessException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ } catch(IllegalArgumentException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ } catch(InvocationTargetException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ }
+ // Is mobile data connected ?
+ boolean mobileConnected = mobile != null && mobile.isConnected();
+
+ // Strings aren't loaded from resources as this activity is temporary
+ String mobileStatus;
+ if(mobileAvailable) mobileStatus = "Available, ";
+ else mobileStatus = "Not available, ";
+ if(mobileEnabled) mobileStatus += "enabled, ";
+ else mobileStatus += "not enabled, ";
+ if(mobileConnected) mobileStatus += "connected";
+ else mobileStatus += "not connected";
+ statusMap.put("Mobile data:", mobileStatus);
+
+ // Is wifi available?
+ NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
+ boolean wifiAvailable = wifi != null && wifi.isAvailable();
+ // Is wifi enabled?
+ WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
+ boolean wifiEnabled = wm != null &&
+ wm.getWifiState() == WIFI_STATE_ENABLED;
+ // Is wifi connected?
+ boolean wifiConnected = wifi != null && wifi.isConnected();
+
+ String wifiStatus;
+ if(wifiAvailable) wifiStatus = "Available, ";
+ else wifiStatus = "Not available, ";
+ if(wifiEnabled) wifiStatus += "enabled, ";
+ else wifiStatus += "not enabled, ";
+ if(wifiConnected) wifiStatus += "connected";
+ else wifiStatus += "not connected";
+ statusMap.put("Wi-Fi:", wifiStatus);
+
+ // Is Bluetooth available?
+ BluetoothAdapter bt = null;
+ try {
+ bt = androidExecutor.call(new Callable() {
+ public BluetoothAdapter call() throws Exception {
+ return BluetoothAdapter.getDefaultAdapter();
+ }
+ });
+ } catch(InterruptedException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ } catch(ExecutionException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ }
+ boolean btAvailable = bt != null;
+ // Is Bluetooth enabled?
+ boolean btEnabled = bt != null && bt.isEnabled() &&
+ !StringUtils.isNullOrEmpty(bt.getAddress());
+ // Is Bluetooth connectable?
+ boolean btConnectable = bt != null &&
+ (bt.getScanMode() == SCAN_MODE_CONNECTABLE ||
+ bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ // Is Bluetooth discoverable?
+ boolean btDiscoverable = bt != null &&
+ bt.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+
+ String btStatus;
+ if(btAvailable) btStatus = "Available, ";
+ else btStatus = "Not available, ";
+ if(btEnabled) btStatus += "enabled, ";
+ else btStatus += "not enabled, ";
+ if(btConnectable) btStatus += "connectable, ";
+ else btStatus += "not connectable, ";
+ if(btDiscoverable) btStatus += "discoverable";
+ else btStatus += "not discoverable";
+ statusMap.put("Bluetooth:", btStatus);
+
+ Plugin torPlugin = pluginManager.getPlugin(new TransportId("tor"));
+ boolean torPluginEnabled = torPlugin != null;
+ boolean torPluginRunning = torPlugin != null && torPlugin.isRunning();
+
+ String torPluginStatus;
+ if(torPluginEnabled) torPluginStatus = "Enabled, ";
+ else torPluginStatus = "Not enabled, ";
+ if(torPluginRunning) torPluginStatus += "running";
+ else torPluginStatus += "not running";
+ statusMap.put("Tor plugin:", torPluginStatus);
+
+ Plugin lanPlugin = pluginManager.getPlugin(new TransportId("lan"));
+ boolean lanPluginEnabled = lanPlugin != null;
+ boolean lanPluginRunning = lanPlugin != null && lanPlugin.isRunning();
+
+ String lanPluginStatus;
+ if(lanPluginEnabled) lanPluginStatus = "Enabled, ";
+ else lanPluginStatus = "Not enabled, ";
+ if(lanPluginRunning) lanPluginStatus += "running";
+ else lanPluginStatus += "not running";
+ statusMap.put("LAN plugin:", lanPluginStatus);
+
+ Plugin btPlugin = pluginManager.getPlugin(new TransportId("bt"));
+ boolean btPluginEnabled = btPlugin != null;
+ boolean btPluginRunning = btPlugin != null && btPlugin.isRunning();
+
+ String btPluginStatus;
+ if(btPluginEnabled) btPluginStatus = "Enabled, ";
+ else btPluginStatus = "Not enabled, ";
+ if(btPluginRunning) btPluginStatus += "running";
+ else btPluginStatus += "not running";
+ statusMap.put("Bluetooth plugin:", btPluginStatus);
+
+ StringBuilder log = new StringBuilder();
+ try {
+ Runtime runtime = Runtime.getRuntime();
+ Process process = runtime.exec("logcat -d -s TorPlugin");
+ Scanner scanner = new Scanner(process.getInputStream());
+ while(scanner.hasNextLine()) {
+ log.append(scanner.nextLine());
+ log.append('\n');
+ }
+ scanner.close();
+ } catch(IOException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ }
+ statusMap.put("Tor log:", log.toString());
+
+ return Collections.unmodifiableMap(statusMap);
+ }
+
+ private void share() {
+ new AsyncTask>() {
+
+ protected Map doInBackground(Void... args) {
+ return getStatusMap();
+ }
+
+ protected void onPostExecute(Map result) {
+ try {
+ File shared = Environment.getExternalStorageDirectory();
+ temp = File.createTempFile("debug", "txt", shared);
+ if(LOG.isLoggable(INFO))
+ LOG.info("Writing to " + temp.getPath());
+ PrintStream p = new PrintStream(new FileOutputStream(temp));
+ for(Entry e : result.entrySet()) {
+ p.println(e.getKey());
+ p.println(e.getValue());
+ p.println();
+ }
+ p.flush();
+ p.close();
+ sendEmail(Uri.fromFile(temp));
+ } catch(IOException e) {
+ if(LOG.isLoggable(WARNING))
+ LOG.log(WARNING, e.toString(), e);
+ }
+ }
+ }.execute();
+ }
+
+ private void sendEmail(Uri attachment) {
+ Intent i = new Intent(ACTION_SEND);
+ i.setType("message/rfc822");
+ i.putExtra(EXTRA_EMAIL, new String[] { "debug@briarproject.org" });
+ i.putExtra(EXTRA_SUBJECT, "Debugging information");
+ i.putExtra(EXTRA_STREAM, attachment);
+ startActivity(Intent.createChooser(i, "Send to developers"));
+ }
+}
diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
index b2609f435..4a875f5fb 100644
--- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
@@ -68,6 +68,7 @@ class DroidtoothPlugin implements DuplexPlugin {
private volatile boolean running = false;
private volatile boolean wasEnabled = false, isEnabled = false;
+ private volatile BluetoothServerSocket socket = null;
// Non-null if running has ever been true
private volatile BluetoothAdapter adapter = null;
@@ -149,7 +150,8 @@ class DroidtoothPlugin implements DuplexPlugin {
tryToClose(ss);
return;
}
- acceptContactConnections(ss);
+ socket = ss;
+ acceptContactConnections();
}
private boolean enableBluetooth() {
@@ -198,15 +200,15 @@ class DroidtoothPlugin implements DuplexPlugin {
}
}
- private void acceptContactConnections(BluetoothServerSocket ss) {
+ private void acceptContactConnections() {
while(true) {
BluetoothSocket s;
try {
- s = ss.accept();
+ s = socket.accept();
} catch(IOException e) {
// This is expected when the socket is closed
if(LOG.isLoggable(INFO)) LOG.log(INFO, e.toString(), e);
- tryToClose(ss);
+ tryToClose(socket);
return;
}
callback.incomingConnectionCreated(wrapSocket(s));
@@ -220,6 +222,7 @@ class DroidtoothPlugin implements DuplexPlugin {
public void stop() {
running = false;
+ if(socket != null) tryToClose(socket);
// Disable Bluetooth if we enabled it at startup
if(isEnabled && !wasEnabled) disableBluetooth();
}
@@ -246,6 +249,10 @@ class DroidtoothPlugin implements DuplexPlugin {
}
}
+ public boolean isRunning() {
+ return running && socket != null;
+ }
+
public boolean shouldPoll() {
return true;
}
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index ed526aee2..80ac29e95 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -72,7 +72,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
private final File torDirectory, torFile, geoIpFile, configFile, doneFile;
private final File cookieFile, pidFile, hostnameFile;
- private volatile boolean running = false;
+ private volatile boolean running = false, networkEnabled = false;
private volatile Process tor = null;
private volatile int pid = -1;
private volatile ServerSocket socket = null;
@@ -509,6 +509,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
if(!running) return;
if(LOG.isLoggable(INFO)) LOG.info("Enabling network: " + enable);
controlConnection.setConf("DisableNetwork", enable ? "0" : "1");
+ networkEnabled = enable;
}
public void stop() throws IOException {
@@ -534,6 +535,10 @@ class TorPlugin implements DuplexPlugin, EventHandler {
}
}
+ public boolean isRunning() {
+ return running && networkEnabled;
+ }
+
public boolean shouldPoll() {
return true;
}
diff --git a/briar-api/src/org/briarproject/api/plugins/Plugin.java b/briar-api/src/org/briarproject/api/plugins/Plugin.java
index 0eb66620e..3389a7357 100644
--- a/briar-api/src/org/briarproject/api/plugins/Plugin.java
+++ b/briar-api/src/org/briarproject/api/plugins/Plugin.java
@@ -23,6 +23,9 @@ public interface Plugin {
/** Stops the plugin. */
void stop() throws IOException;
+ /** Returns true if the plugin is running. */
+ boolean isRunning();
+
/**
* Returns true if the plugin's {@link #poll(Collection)} method should be
* called periodically to attempt to establish connections.
diff --git a/briar-api/src/org/briarproject/api/plugins/PluginManager.java b/briar-api/src/org/briarproject/api/plugins/PluginManager.java
index 330de8669..efc336cf0 100644
--- a/briar-api/src/org/briarproject/api/plugins/PluginManager.java
+++ b/briar-api/src/org/briarproject/api/plugins/PluginManager.java
@@ -2,6 +2,7 @@ package org.briarproject.api.plugins;
import java.util.Collection;
+import org.briarproject.api.TransportId;
import org.briarproject.api.lifecycle.Service;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
@@ -11,6 +12,12 @@ import org.briarproject.api.plugins.duplex.DuplexPlugin;
*/
public interface PluginManager extends Service {
+ /**
+ * Returns the plugin for the given transport, or null if no such plugin
+ * is running.
+ */
+ Plugin getPlugin(TransportId t);
+
/** Returns any running duplex plugins that support invitations. */
Collection getInvitationPlugins();
}
diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
index b78aba1bb..6dee08bb2 100644
--- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
@@ -9,6 +9,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -56,6 +57,7 @@ class PluginManagerImpl implements PluginManager {
private final Poller poller;
private final ConnectionDispatcher dispatcher;
private final UiCallback uiCallback;
+ private final Map plugins;
private final List simplexPlugins;
private final List duplexPlugins;
@@ -73,6 +75,7 @@ class PluginManagerImpl implements PluginManager {
this.poller = poller;
this.dispatcher = dispatcher;
this.uiCallback = uiCallback;
+ plugins = new ConcurrentHashMap();
simplexPlugins = new CopyOnWriteArrayList();
duplexPlugins = new CopyOnWriteArrayList();
}
@@ -104,10 +107,7 @@ class PluginManagerImpl implements PluginManager {
}
// Start the poller
if(LOG.isLoggable(INFO)) LOG.info("Starting poller");
- List plugins = new ArrayList();
- plugins.addAll(simplexPlugins);
- plugins.addAll(duplexPlugins);
- poller.start(Collections.unmodifiableList(plugins));
+ poller.start(plugins.values());
return true;
}
@@ -115,8 +115,7 @@ class PluginManagerImpl implements PluginManager {
// Stop the poller
if(LOG.isLoggable(INFO)) LOG.info("Stopping poller");
poller.stop();
- int plugins = simplexPlugins.size() + duplexPlugins.size();
- final CountDownLatch latch = new CountDownLatch(plugins);
+ final CountDownLatch latch = new CountDownLatch(plugins.size());
// Stop the simplex plugins
if(LOG.isLoggable(INFO)) LOG.info("Stopping simplex plugins");
for(SimplexPlugin plugin : simplexPlugins)
@@ -125,6 +124,7 @@ class PluginManagerImpl implements PluginManager {
if(LOG.isLoggable(INFO)) LOG.info("Stopping duplex plugins");
for(DuplexPlugin plugin : duplexPlugins)
pluginExecutor.execute(new PluginStopper(plugin, latch));
+ plugins.clear();
simplexPlugins.clear();
duplexPlugins.clear();
// Wait for all the plugins to stop
@@ -139,6 +139,10 @@ class PluginManagerImpl implements PluginManager {
return true;
}
+ public Plugin getPlugin(TransportId t) {
+ return plugins.get(t);
+ }
+
public Collection getInvitationPlugins() {
List supported = new ArrayList();
for(DuplexPlugin d : duplexPlugins)
@@ -185,6 +189,7 @@ class PluginManagerImpl implements PluginManager {
boolean started = plugin.start();
long duration = clock.currentTimeMillis() - start;
if(started) {
+ plugins.put(id, plugin);
simplexPlugins.add(plugin);
if(LOG.isLoggable(INFO)) {
String name = plugin.getClass().getSimpleName();
@@ -246,6 +251,7 @@ class PluginManagerImpl implements PluginManager {
boolean started = plugin.start();
long duration = clock.currentTimeMillis() - start;
if(started) {
+ plugins.put(id, plugin);
duplexPlugins.add(plugin);
if(LOG.isLoggable(INFO)) {
String name = plugin.getClass().getSimpleName();
diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
index 6b286559a..77ed42e42 100644
--- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
+++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
@@ -55,6 +55,10 @@ public abstract class FilePlugin implements SimplexPlugin {
return maxLatency;
}
+ public boolean isRunning() {
+ return running;
+ }
+
public SimplexTransportReader createReader(ContactId c) {
return null;
}
diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
index 4f483dc89..13401c290 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
@@ -146,6 +146,10 @@ abstract class TcpPlugin implements DuplexPlugin {
if(socket != null) tryToClose(socket);
}
+ public boolean isRunning() {
+ return running && socket != null && socket.isBound();
+ }
+
public boolean shouldPoll() {
return true;
}
diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
index 3bc65ce0f..4572df83e 100644
--- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
@@ -172,6 +172,10 @@ class BluetoothPlugin implements DuplexPlugin {
tryToClose(socket);
}
+ public boolean isRunning() {
+ return running;
+ }
+
public boolean shouldPoll() {
return true;
}
diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
index 58f1c421e..4913cd82d 100644
--- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
@@ -98,23 +98,8 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
}
}
- private boolean resetModem() {
- if(!running) return false;
- for(String portName : serialPortList.getPortNames()) {
- if(LOG.isLoggable(INFO))
- LOG.info("Trying to initialise modem on " + portName);
- modem = modemFactory.createModem(this, portName);
- try {
- if(!modem.start()) continue;
- if(LOG.isLoggable(INFO))
- LOG.info("Initialised modem on " + portName);
- return true;
- } catch(IOException e) {
- if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- }
- }
- running = false;
- return false;
+ public boolean isRunning() {
+ return running;
}
public boolean shouldPoll() {
@@ -180,6 +165,25 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
}
}
+ private boolean resetModem() {
+ if(!running) return false;
+ for(String portName : serialPortList.getPortNames()) {
+ if(LOG.isLoggable(INFO))
+ LOG.info("Trying to initialise modem on " + portName);
+ modem = modemFactory.createModem(this, portName);
+ try {
+ if(!modem.start()) continue;
+ if(LOG.isLoggable(INFO))
+ LOG.info("Initialised modem on " + portName);
+ return true;
+ } catch(IOException e) {
+ if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ }
+ }
+ running = false;
+ return false;
+ }
+
public DuplexTransportConnection createConnection(ContactId c) {
if(!running) return null;
// Get the ISO 3166 code for the caller's country