Android Bluetooth plugin binds a socket each time BT is enabled.

Dev task #80.
This commit is contained in:
akwizgran
2014-03-13 18:39:53 +00:00
parent 26a4841a8c
commit 5755aed362

View File

@@ -68,9 +68,10 @@ class DroidtoothPlugin implements DuplexPlugin {
private volatile boolean running = false; private volatile boolean running = false;
private volatile boolean wasDisabled = false; private volatile boolean wasDisabled = false;
private volatile BluetoothStateReceiver receiver = null;
private volatile BluetoothServerSocket socket = null; private volatile BluetoothServerSocket socket = null;
// Non-null if running has ever been true // Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null; private volatile BluetoothAdapter adapter = null;
DroidtoothPlugin(Executor pluginExecutor, AndroidExecutor androidExecutor, DroidtoothPlugin(Executor pluginExecutor, AndroidExecutor androidExecutor,
@@ -120,66 +121,56 @@ class DroidtoothPlugin implements DuplexPlugin {
return false; return false;
} }
running = true; running = true;
pluginExecutor.execute(new Runnable() { // Listen for changes to the Bluetooth state
public void run() { IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED);
bind(); receiver = new BluetoothStateReceiver();
appContext.registerReceiver(receiver, filter);
// If Bluetooth is enabled, bind a socket - otherwise enable it
if(adapter.isEnabled()) {
bind();
} else if(callback.getConfig().getBoolean("enable", true)) {
if(adapter.enable()) {
LOG.info("Enabling Bluetooth");
wasDisabled = true;
} else {
LOG.info("Could not enable Bluetooth");
} }
}); } else {
LOG.info("Not enabling Bluetooth");
}
return true; return true;
} }
private void bind() { private void bind() {
if(!running) return; pluginExecutor.execute(new Runnable() {
if(!enableBluetooth()) return; public void run() {
if(LOG.isLoggable(INFO)) if(!running) return;
LOG.info("Local address " + adapter.getAddress()); if(!adapter.isEnabled()) return;
// Advertise the Bluetooth address to contacts if(LOG.isLoggable(INFO))
TransportProperties p = new TransportProperties(); LOG.info("Local address " + adapter.getAddress());
p.put("address", adapter.getAddress()); // Advertise the Bluetooth address to contacts
callback.mergeLocalProperties(p); TransportProperties p = new TransportProperties();
// Bind a server socket to accept connections from contacts p.put("address", adapter.getAddress());
BluetoothServerSocket ss = null; callback.mergeLocalProperties(p);
try { // Bind a server socket to accept connections from contacts
ss = InsecureBluetooth.listen(adapter, "RFCOMM", getUuid()); BluetoothServerSocket ss = null;
} catch(IOException e) { try {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); ss = InsecureBluetooth.listen(adapter, "RFCOMM", getUuid());
tryToClose(ss); } catch(IOException e) {
return; if(LOG.isLoggable(WARNING))
} LOG.log(WARNING, e.toString(), e);
if(!running) { tryToClose(ss);
tryToClose(ss); return;
return; }
} if(!running) {
socket = ss; tryToClose(ss);
acceptContactConnections(); return;
} }
LOG.info("Socket bound");
private boolean enableBluetooth() { socket = ss;
if(adapter.isEnabled()) return true; acceptContactConnections();
if(!callback.getConfig().getBoolean("enable", true)) {
LOG.info("Not enabling Bluetooth");
return false;
}
wasDisabled = true;
// Try to enable the adapter and wait for the result
LOG.info("Enabling Bluetooth");
IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED);
BluetoothStateReceiver receiver = new BluetoothStateReceiver();
appContext.registerReceiver(receiver, filter);
try {
if(adapter.enable()) {
boolean enabled = receiver.waitForStateChange();
if(LOG.isLoggable(INFO)) LOG.info("Enabled: " + enabled);
return enabled;
} else {
LOG.info("Could not enable Bluetooth");
return false;
} }
} catch(InterruptedException e) { });
LOG.warning("Interrupted while enabling Bluetooth");
Thread.currentThread().interrupt();
return false;
}
} }
private UUID getUuid() { private UUID getUuid() {
@@ -204,7 +195,7 @@ class DroidtoothPlugin implements DuplexPlugin {
} }
private void acceptContactConnections() { private void acceptContactConnections() {
while(true) { while(running) {
BluetoothSocket s; BluetoothSocket s;
try { try {
s = socket.accept(); s = socket.accept();
@@ -215,7 +206,6 @@ class DroidtoothPlugin implements DuplexPlugin {
return; return;
} }
callback.incomingConnectionCreated(wrapSocket(s)); callback.incomingConnectionCreated(wrapSocket(s));
if(!running) return;
} }
} }
@@ -225,33 +215,17 @@ class DroidtoothPlugin implements DuplexPlugin {
public void stop() { public void stop() {
running = false; running = false;
if(socket != null) tryToClose(socket); if(receiver != null) appContext.unregisterReceiver(receiver);
// Disable Bluetooth if we enabled it at any point tryToClose(socket);
if(wasDisabled) disableBluetooth(); // Disable Bluetooth if we enabled it and it's still enabled
} if(wasDisabled && adapter.isEnabled()) {
if(adapter.disable()) LOG.info("Disabling Bluetooth");
private void disableBluetooth() { else LOG.info("Could not disable Bluetooth");
if(!adapter.isEnabled()) return;
// Try to disable the adapter and wait for the result
LOG.info("Disabling Bluetooth");
IntentFilter filter = new IntentFilter(ACTION_STATE_CHANGED);
BluetoothStateReceiver receiver = new BluetoothStateReceiver();
appContext.registerReceiver(receiver, filter);
try {
if(adapter.disable()) {
boolean enabled = receiver.waitForStateChange();
if(LOG.isLoggable(INFO)) LOG.info("Enabled: " + enabled);
} else {
LOG.info("Could not disable Bluetooth");
}
} catch(InterruptedException e) {
LOG.warning("Interrupted while disabling Bluetooth");
Thread.currentThread().interrupt();
} }
} }
public boolean isRunning() { public boolean isRunning() {
return running && socket != null; return running && adapter.isEnabled();
} }
public boolean shouldPoll() { public boolean shouldPoll() {
@@ -379,28 +353,18 @@ class DroidtoothPlugin implements DuplexPlugin {
return null; return null;
} }
private static class BluetoothStateReceiver extends BroadcastReceiver { private class BluetoothStateReceiver extends BroadcastReceiver {
private final CountDownLatch finished = new CountDownLatch(1);
private volatile boolean enabled = false;
public void onReceive(Context ctx, Intent intent) { public void onReceive(Context ctx, Intent intent) {
int state = intent.getIntExtra(EXTRA_STATE, 0); int state = intent.getIntExtra(EXTRA_STATE, 0);
if(state == STATE_ON) { if(state == STATE_ON) {
enabled = true; LOG.info("Bluetooth enabled");
ctx.unregisterReceiver(this); bind();
finished.countDown();
} else if(state == STATE_OFF) { } else if(state == STATE_OFF) {
ctx.unregisterReceiver(this); LOG.info("Bluetooth disabled");
finished.countDown(); tryToClose(socket);
} }
} }
boolean waitForStateChange() throws InterruptedException {
finished.await();
return enabled;
}
} }
private class DiscoveryThread extends Thread { private class DiscoveryThread extends Thread {