From da80f3d219c0c05568db0cb9a8910f02cc281d47 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 2 Jan 2015 21:38:52 +0100 Subject: o Getting closer to something that actually work. --- .../io/trygvis/android/bt/BtActionExecutor.java | 358 ++++++++++----------- .../java/io/trygvis/android/bt/BtCallback.java | 4 + .../main/java/io/trygvis/android/bt/BtDevice.java | 40 ++- .../io/trygvis/android/bt/BtDeviceListener.java | 4 - .../main/java/io/trygvis/android/bt/BtService.java | 50 +-- .../io/trygvis/android/bt/DefaultBtService.java | 100 ++++-- 6 files changed, 301 insertions(+), 255 deletions(-) delete mode 100644 app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java (limited to 'app/src/main/java/io/trygvis/android/bt') diff --git a/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java b/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java index 8cbf87c..984c738 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java +++ b/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java @@ -12,6 +12,9 @@ import java.util.Iterator; import java.util.List; import java.util.Queue; +import io.trygvis.android.F2; +import io.trygvis.android.Function; + import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicChanged; import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicRead; import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicWrite; @@ -19,239 +22,146 @@ import static io.trygvis.android.bt.BtActionExecutor.EventType.onConnectionState import static io.trygvis.android.bt.BtActionExecutor.EventType.onDescriptorRead; import static io.trygvis.android.bt.BtActionExecutor.EventType.onDescriptorWrite; import static io.trygvis.android.bt.BtActionExecutor.EventType.onFailure; +import static io.trygvis.android.bt.BtActionExecutor.EventType.onFinally; import static io.trygvis.android.bt.BtActionExecutor.EventType.onReliableWriteCompleted; import static io.trygvis.android.bt.BtActionExecutor.EventType.onServicesDiscovered; public class BtActionExecutor { private final static String TAG = BtActionExecutor.class.getSimpleName(); private final Queue actionQ = new ArrayDeque<>(); + private final Queue failureQ = new ArrayDeque<>(); private final Queue finallyQ = new ArrayDeque<>(); - private final List remoteRssi = new ArrayList<>(); - - public BtActionExecutor() { - } - - public BtActionExecutor(BtCallback first) { - actionQ.add(first); - } -// public static final BtCallback waitForIt = new BtCallback("Wait for it") { -// @Override -// public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { -// Log.w(TAG, "wait for it...!"); -// return true; -// } -// }; - -// public synchronized BtActionExecutor onSuccess(BtCallback btCallback) { -// actionQ.add(btCallback); -// return this; -// } - - public synchronized BtActionExecutor onConnectionStateChange(OnConnectionStateChange callback) { + public synchronized BtActionExecutor onConnectionStateChange(F2 callback) { actionQ.add(new BtCallback("onConnectionStateChange") { @Override public boolean onConnectionStateChange(BluetoothGatt gatt, int newState) { - return callback.onConnectionStateChange(gatt, newState); + return callback.apply(gatt, newState); } }); return this; } - public synchronized BtActionExecutor onServicesDiscovered(OnServicesDiscovered callback) { + public synchronized BtActionExecutor onServicesDiscovered(Function callback) { actionQ.add(new BtCallback("onServicesDiscovered") { @Override public boolean onServicesDiscovered(BluetoothGatt gatt) { - return callback.onServicesDiscovered(gatt); + return callback.apply(gatt); } }); return this; } - public synchronized BtActionExecutor onCharacteristicRead(OnCharacteristicRead callback) { + public synchronized BtActionExecutor onCharacteristicRead(F2 callback) { actionQ.add(new BtCallback("onCharacteristicRead") { @Override public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicRead(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onCharacteristicWrite(OnCharacteristicWrite callback) { + public synchronized BtActionExecutor onCharacteristicWrite(F2 callback) { actionQ.add(new BtCallback("onCharacteristicWrite") { @Override public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicWrite(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onCharacteristicChanged(OnCharacteristicChanged callback) { + public synchronized BtActionExecutor onCharacteristicChanged(F2 callback) { actionQ.add(new BtCallback("onCharacteristicChanged") { @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicChanged(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onDescriptorRead(OnDescriptorRead callback) { + public synchronized BtActionExecutor onDescriptorRead(F2 callback) { actionQ.add(new BtCallback("onDescriptorRead") { @Override public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { - return callback.onDescriptorRead(gatt, descriptor); + return callback.apply(gatt, descriptor); } }); return this; } - public synchronized BtActionExecutor onDescriptorWrite(OnDescriptorWrite callback) { + public synchronized BtActionExecutor onDescriptorWrite(F2 callback) { actionQ.add(new BtCallback("onDescriptorWrite") { @Override public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { - return callback.onDescriptorWrite(gatt, descriptor); + return callback.apply(gatt, descriptor); } }); return this; } - public synchronized BtActionExecutor onReliableWriteCompleted(OnReliableWriteCompleted callback) { + public synchronized BtActionExecutor onReliableWriteCompleted(Function callback) { actionQ.add(new BtCallback("onReliableWriteCompleted") { @Override public boolean onReliableWriteCompleted(BluetoothGatt gatt) { - return callback.onReliableWriteCompleted(gatt); + return callback.apply(gatt); } }); return this; } - public synchronized BtActionExecutor onReadRemoteRssi(OnReadRemoteRssi callback) { + public synchronized BtActionExecutor onReadRemoteRssi(F2 callback) { actionQ.add(new BtCallback("onReadRemoteRssi") { @Override public boolean onReadRemoteRssi(BluetoothGatt gatt, int rssi) { - return callback.onReadRemoteRssi(gatt, rssi); + return callback.apply(gatt, rssi); } }); return this; } - public synchronized BtActionExecutor onFailure(OnFailure callback) { - actionQ.add(new BtCallback("onFailure") { + public synchronized BtActionExecutor onFailure(Runnable callback) { + failureQ.add(new BtCallback("onFailure") { @Override public void onFailure() { - callback.onFailure(); + callback.run(); } }); return this; } - public static interface OnConnectionStateChange { - boolean onConnectionStateChange(BluetoothGatt gatt, int newState); - } - - public static interface OnServicesDiscovered { - boolean onServicesDiscovered(BluetoothGatt gatt); - } - - public static interface OnCharacteristicRead { - boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnCharacteristicWrite { - boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnCharacteristicChanged { - boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnDescriptorRead { - boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor); - } - - public static interface OnDescriptorWrite { - boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor); - } - - public static interface OnReliableWriteCompleted { - boolean onReliableWriteCompleted(BluetoothGatt gatt); - } - - public static interface OnReadRemoteRssi { - boolean onReadRemoteRssi(BluetoothGatt gatt, int rssi); - } - - public static interface OnFailure { - void onFailure(); - } - - public synchronized BtActionExecutor addFinally(BtCallback btCallback) { - finallyQ.add(btCallback); + public synchronized BtActionExecutor onFinally(Runnable callback) { + finallyQ.add(new BtCallback("finally") { + @Override + public void onFinally() { + callback.run(); + } + }); return this; } -// public synchronized BtActionExecutor onRemoteRssi(BluetoothGattCallback callback) { -// remoteRssi.add(callback); -// return this; -// } - - void onEvent(EventType key, String values, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) { - if (status != BluetoothGatt.GATT_SUCCESS) { - Log.w(TAG, "Operation failed: " + key + ", " + values); - doFinally(); - return; - } - - Log.i(TAG, "Bt action completed successfully: callback=" + key); - - BtCallback btCallback; - synchronized (this) { - if (actionQ.isEmpty()) { - Log.d(TAG, "All Bluetooth actions are done"); + public String toString() { + StringBuilder s = new StringBuilder("Queue: "); - doFinally(); - return; - } + Iterator it = actionQ.iterator(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // ignore + int i = 0; + while (it.hasNext()) { + BtCallback c = it.next(); + if (i > 0) { + s.append(", "); } - btCallback = actionQ.remove(); - Log.i(TAG, "Executing bt action: " + btCallback.name); + s.append(c.name); + i++; } - try { - boolean ok = callCallback(key, gatt, characteristic, descriptor, newState, btCallback); - - if (!ok) { - Log.w(TAG, "The callback don't want to continue."); - doFinally(); - } - - if (actionQ.isEmpty()) { - Log.i(TAG, "The queue is empty"); - } - } catch (NotOverriddenException e) { - Log.w(TAG, "Unexpected callback by listener: " + key); - doFinally(); - } + return s.toString(); } - private void doFinally() { - actionQ.clear(); - - for (BtCallback callback = finallyQ.poll(); callback != null; callback = finallyQ.poll()) { - try { - callCallback(onFailure, null, null, null, 0, callback); - } catch (NotOverriddenException e) { - return; - } - } + public BluetoothGattCallback asCallback() { + return new MyBluetoothGattCallback(); } enum EventType { @@ -264,10 +174,13 @@ public class BtActionExecutor { onDescriptorWrite, onReliableWriteCompleted, + onReadRemoteRssi, + onFailure, + onFinally, } - private Boolean callCallback(EventType key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int newState, BtCallback btCallback) { + private static Boolean callCallback(EventType key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int newState, BtCallback btCallback) { switch (key) { case onConnectionStateChange: return btCallback.onConnectionStateChange(gatt, newState); @@ -289,78 +202,155 @@ public class BtActionExecutor { case onFailure: btCallback.onFailure(); return null; + case onFinally: + btCallback.onFinally(); + return null; default: Log.w(TAG, "Unknown callback: " + key); return null; } } - public String toString() { - StringBuilder s = new StringBuilder("Queue: "); + private class MyBluetoothGattCallback extends BluetoothGattCallback { - Iterator it = actionQ.iterator(); + private Queue initialActionQ = new ArrayDeque<>(actionQ); + private List events = new ArrayList<>(); - int i = 0; - while (it.hasNext()) { - BtCallback c = it.next(); - if (i > 0) { - s.append(", "); - } - s.append(c.name); - i++; - } + void onEvent(EventType key, String values, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) { + boolean success = status == BluetoothGatt.GATT_SUCCESS; + events.add(key + ", " + values + ", success=" + success); - return s.toString(); - } + Log.i(TAG, "Operation failed: " + key + ", " + values + ", success=" + success); - public BluetoothGattCallback asCallback() { - return new BluetoothGattCallback() { - @Override - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - onEvent(onConnectionStateChange, "status=" + status + ", newState=" + newState, gatt, null, null, status, newState); + if (!success) { + doFailure(); + return; } - @Override - public void onServicesDiscovered(BluetoothGatt gatt, int status) { - onEvent(onServicesDiscovered, "status=" + status, gatt, null, null, status, 9); - } + BtCallback btCallback; + synchronized (this) { + if (actionQ.isEmpty()) { + Log.d(TAG, "All Bluetooth actions are done"); - @Override - public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { - onEvent(onCharacteristicRead, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); - } + doFinally(); + return; + } - @Override - public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { - onEvent(onCharacteristicWrite, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignore + } + btCallback = actionQ.remove(); + Log.i(TAG, "Executing bt action: " + btCallback.name); } - @Override - public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - onEvent(onCharacteristicChanged, "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0); + try { + boolean ok = callCallback(key, gatt, characteristic, descriptor, newState, btCallback); + + if (!ok) { + Log.w(TAG, "The callback don't want to continue."); + doFinally(); + } + + if (actionQ.isEmpty()) { + Log.i(TAG, "The queue is empty"); + } + } catch (NotOverriddenException e) { + Log.w(TAG, "Unexpected callback by listener: " + key); + doFailure(); } + } - @Override - public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - onEvent(onDescriptorRead, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + private void doFailure() { + StringBuilder msg = new StringBuilder(); + + msg.append("Expected events: \n"); + for (BtCallback cb : initialActionQ) { + msg.append(" ").append(cb.name).append("\n"); } - @Override - public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - onEvent(onDescriptorWrite, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + msg.append("Actual events: \n"); + for (String event : events) { + msg.append(" ").append(event).append("\n"); } - @Override - public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { - onEvent(onReliableWriteCompleted, "status=" + status, gatt, null, null, status, 0); + Log.w(TAG, msg.toString()); + + Log.w(TAG, "Executing " + failureQ.size() + " failure handlers"); + + for (BtCallback callback = failureQ.poll(); callback != null; callback = failureQ.poll()) { + try { + callCallback(onFailure, null, null, null, 0, callback); + } catch (NotOverriddenException e) { + return; + } } - @Override - public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { - for (BluetoothGattCallback callback : remoteRssi) { - callback.onReadRemoteRssi(gatt, rssi, status); + doFinally(); + } + + private void doFinally() { + actionQ.clear(); + + Log.w(TAG, "Executing " + finallyQ.size() + " finally handlers"); + + for (BtCallback callback = finallyQ.poll(); callback != null; callback = finallyQ.poll()) { + try { + callCallback(onFinally, null, null, null, 0, callback); + } catch (NotOverriddenException e) { + return; } } - }; + } + + // ----------------------------------------------------------------------- + // + // ----------------------------------------------------------------------- + + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + onEvent(onConnectionStateChange, "status=" + status + ", newState=" + newState, gatt, null, null, status, newState); + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + onEvent(onServicesDiscovered, "status=" + status, gatt, null, null, status, 9); + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + onEvent(onCharacteristicRead, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + } + + @Override + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + onEvent(onCharacteristicWrite, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + onEvent(onCharacteristicChanged, "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0); + } + + @Override + public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + onEvent(onDescriptorRead, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + onEvent(onDescriptorWrite, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + } + + @Override + public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { + onEvent(onReliableWriteCompleted, "status=" + status, gatt, null, null, status, 0); + } + + @Override + public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { +// onEvent(onReadRemoteRssi, "status=" + status, gatt, null, null, status, 0); + } } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtCallback.java b/app/src/main/java/io/trygvis/android/bt/BtCallback.java index 7702962..29ea9e1 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtCallback.java +++ b/app/src/main/java/io/trygvis/android/bt/BtCallback.java @@ -50,4 +50,8 @@ public class BtCallback { public void onFailure() { throw new NotOverriddenException(); } + + public void onFinally() { + throw new NotOverriddenException(); + } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtDevice.java b/app/src/main/java/io/trygvis/android/bt/BtDevice.java index ba10d2d..e34e9ea 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtDevice.java +++ b/app/src/main/java/io/trygvis/android/bt/BtDevice.java @@ -3,6 +3,8 @@ package io.trygvis.android.bt; import android.bluetooth.BluetoothDevice; import android.util.Log; +import io.trygvis.android.Function; + public class BtDevice { private final static String TAG = BtDevice.class.getSimpleName(); @@ -14,31 +16,22 @@ public class BtDevice { private boolean seenNow; - private BtDeviceListener l = null; - - private BtDeviceListener listener = new BtDeviceListener() { - }; + public static interface BtDeviceWrapper { + BtDevice getBtDevice(); + } - public BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, A tag, Integer rssi, BtScanResult scanResult) { + BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, Function, A> tagConstructor, Integer rssi, BtScanResult scanResult) { this.btService = btService; this.bluetoothDevice = bluetoothDevice; - this.tag = tag; + this.tag = tagConstructor.apply(this); this.rssi = rssi; this.scanResult = scanResult; } - public void addListener(BtDeviceListener listener) { - this.l = listener; - } - public A getTag() { return tag; } - public void setTag(A tag) { - this.tag = tag; - } - public String getAddress() { return bluetoothDevice.getAddress(); } @@ -65,4 +58,23 @@ public class BtDevice { public String toString() { return "BtDevice{address=" + bluetoothDevice.getAddress() + '}'; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BtDevice other = (BtDevice) o; + + return getAddress().equals(other.getAddress()); + } + + @Override + public int hashCode() { + return getAddress().hashCode(); + } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java b/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java deleted file mode 100644 index 57eabc6..0000000 --- a/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.trygvis.android.bt; - -public interface BtDeviceListener { -} diff --git a/app/src/main/java/io/trygvis/android/bt/BtService.java b/app/src/main/java/io/trygvis/android/bt/BtService.java index 123be3a..968a4a8 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtService.java +++ b/app/src/main/java/io/trygvis/android/bt/BtService.java @@ -1,12 +1,17 @@ package io.trygvis.android.bt; -import android.os.Binder; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; -import java.util.List; +import java.util.Collection; -public interface BtService { +import io.trygvis.android.Function; - boolean initialize(BtServiceListener btServiceListener, Supplier dataSupplier); +public interface BtService> { + + boolean initialize(Function, A> tagConstructor); void clearCache(); @@ -16,40 +21,35 @@ public interface BtService { void stopScanning(); -// BtDevice getDevice(String macAddress); + BtDevice getDevice(String address); - List> getDevices(); + A getTag(String address); - interface Supplier { - A get(); - } + Collection> getDevices(); - interface BtServiceListener { - void onScanStarted(); + Collection getTags(); - void onNewDevice(BtDevice device); + public static class BtServiceListenerBroadcastReceiver extends BroadcastReceiver { - void onScanStopped(); - } + public static final String INTENT_NAME = BtServiceListenerBroadcastReceiver.class.getName(); - public abstract class AbstractBtServiceListener implements BtServiceListener { + public static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_NAME); - public void onScanStarted() { - } + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(INTENT_NAME)) { + return; + } - public void onScanStopped() { + DefaultBtService.dispatchEvent(intent, this); } - } - public class LocalBinder extends Binder { - private final BtService service; + public void onScanStarted() { + } - public LocalBinder(BtService service) { - this.service = service; + public void onNewDevice(String address) { } - public BtService getService() { - return service; + public void onScanStopped() { } } } diff --git a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java index 8638544..51d84af 100644 --- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java +++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java @@ -13,12 +13,17 @@ import android.util.Log; import android.widget.Toast; import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import io.trygvis.android.Function; +import io.trygvis.android.LocalBinder; import io.trygvis.soilmoisture.R; -public class DefaultBtService extends Service implements BtService { +import static java.util.Collections.unmodifiableCollection; + +public class DefaultBtService> extends Service implements BtService { private final static String TAG = DefaultBtService.class.getSimpleName(); private final IBinder binder = new LocalBinder<>(this); @@ -29,19 +34,13 @@ public class DefaultBtService extends Service implements BtService { // State // ----------------------------------------------------------------------- - private BtServiceListener serviceListener = new AbstractBtServiceListener() { - @Override - public void onNewDevice(BtDevice device) { - } - }; - - private Supplier tagConstructor; + private Function, A> tagConstructor; private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; - private final List> devices = new ArrayList<>(); + private final Set> devices = new HashSet<>(); private boolean scanning = false; @@ -50,17 +49,13 @@ public class DefaultBtService extends Service implements BtService { // ----------------------------------------------------------------------- @Override - public boolean initialize(BtServiceListener serviceListener, Supplier dataSupplier) { + public boolean initialize(Function, A> tagConstructor) { if (bluetoothManager != null) { - Log.e(TAG, "Already initialized"); + Log.i(TAG, "Already initialized"); return false; } - this.tagConstructor = dataSupplier; - - if (serviceListener != null) { - this.serviceListener = serviceListener; - } + this.tagConstructor = tagConstructor; // Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. @@ -85,7 +80,7 @@ public class DefaultBtService extends Service implements BtService { return false; } - Log.e(TAG, "Bluetooth initialized"); + Log.i(TAG, "Bluetooth initialized"); return true; } @@ -100,13 +95,15 @@ public class DefaultBtService extends Service implements BtService { @Override public boolean startScanning(long timeoutMs) { + Log.d(TAG, "startScanning, timeoutMs=" + timeoutMs); + if (timeoutMs > 0) { handler.postDelayed(this::stopScanning, timeoutMs); } if (bluetoothAdapter.startLeScan(leScanCallback)) { scanning = true; - serviceListener.onScanStarted(); + sendBroadcast(createScanStarted()); return true; } @@ -115,15 +112,16 @@ public class DefaultBtService extends Service implements BtService { @Override public void stopScanning() { + Log.d(TAG, "stopScanning"); + // This doesn't mind being called twice. bluetoothAdapter.stopLeScan(leScanCallback); scanning = false; - serviceListener.onScanStopped(); + sendBroadcast(createScanStopped()); } -// @Override public BtDevice getDevice(String mac) { BtDevice device = findDevice(mac); @@ -136,8 +134,22 @@ public class DefaultBtService extends Service implements BtService { } @Override - public List> getDevices() { - return Collections.unmodifiableList(devices); + public A getTag(String address) { + return getDevice(address).getTag(); + } + + @Override + public Collection> getDevices() { + return unmodifiableCollection(devices); + } + + @Override + public Collection getTags() { + ArrayList tags = new ArrayList<>(); + for (BtDevice device : devices) { + tags.add(device.getTag()); + } + return tags; } // ----------------------------------------------------------------------- @@ -145,8 +157,6 @@ public class DefaultBtService extends Service implements BtService { // ----------------------------------------------------------------------- private BluetoothAdapter.LeScanCallback leScanCallback = (device, rssi, scanRecord) -> { -// Log.i(TAG, "onLeScan()"); - BtScanResult scanResult = new BtScanResult(scanRecord); register(device, rssi, scanResult); @@ -173,14 +183,48 @@ public class DefaultBtService extends Service implements BtService { } Log.i(TAG, "New device: " + bluetoothDevice.getAddress()); - btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor.get(), rssi, scanResult); + btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor, rssi, scanResult); devices.add(btDevice); - serviceListener.onNewDevice(btDevice); + sendBroadcast(createNewDevice(btDevice.getAddress())); return btDevice; } + private Intent createScanStarted() { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "scanStarted"); + } + + private Intent createScanStopped() { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "scanStopped"); + } + + private Intent createNewDevice(String address) { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "newDevice"). + putExtra("address", address); + } + + public static void dispatchEvent(Intent intent, BtServiceListenerBroadcastReceiver listener) { + String event = intent.getStringExtra("event"); + Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event); + switch (event) { + case "newDevice": + listener.onNewDevice(intent.getStringExtra("address")); + break; + case "scanStarted": + listener.onScanStarted(); + break; + case "scanStopped": + listener.onScanStopped(); + break; + default: + break; + } + } + private BtDevice findDevice(String mac) { for (BtDevice d : devices) { if (d.getAddress().equals(mac)) { -- cgit v1.2.3